DIRECTORY Atom USING [MakeAtom], NodeProps USING [GetProp, nameActive], RefTab USING [Create, Delete, EachPairAction, Fetch, Pairs, Ref, Store], Rope USING [ROPE, Size], TextNode, TextNodeRegistry USING [NotifySet, NotifyProc, ProcSet], Tioga; TextNodeImpl: CEDAR PROGRAM IMPORTS Atom, NodeProps, RefTab, Rope EXPORTS TextNode, TextNodeRegistry = BEGIN Node: TYPE ~ Tioga.Node; Location: TYPE ~ Tioga.Location; ROPE: TYPE ~ Rope.ROPE; ProcSet: TYPE ~ TextNodeRegistry.ProcSet; NotifySet: TYPE ~ TextNodeRegistry.NotifySet; NotifyProc: TYPE ~ TextNodeRegistry.NotifyProc; registrationTable: RefTab.Ref = RefTab.Create[]; notificationTable: RefTab.Ref = RefTab.Create[]; Register: PUBLIC PROC [activity: ATOM, procs: ProcSet] RETURNS [] ~ { NotifyRegistration: RefTab.EachPairAction = { IF val#NIL THEN { notifier: NotifyProc = NARROW[val, NotifySet].registrationNotify; IF notifier#NIL THEN notifier[key, activity, procs.activityOn]; }; }; [] ¬ RefTab.Store[registrationTable, activity, procs]; [] ¬ RefTab.Pairs[notificationTable, NotifyRegistration]; }; UnRegister: PUBLIC PROC [activity: ATOM] RETURNS [] ~ { on: BOOLEAN = IsActivityOn[activity]; NotifyUnRegistration: RefTab.EachPairAction = { IF val#NIL THEN { notifier: NotifyProc = NARROW[val, NotifySet].unRegistrationNotify; IF notifier#NIL THEN notifier[key, activity, on]; }; }; [] ¬ RefTab.Pairs[notificationTable, NotifyUnRegistration]; [] ¬ RefTab.Delete[registrationTable, activity]; }; GetProcs: PUBLIC PROC [activity: ATOM] RETURNS [procs: ProcSet] ~ { RETURN[NARROW[RefTab.Fetch[registrationTable, activity].val]]; }; ActivityOn: PUBLIC PROC [activity: ATOM, on: BOOL ¬ TRUE] RETURNS [wasOn: BOOL] ~ { SetActivity: RefTab.EachPairAction = { enumeratedActivity: ATOM = NARROW[key]; procs: ProcSet = NARROW[val]; NotifyActivityOn: RefTab.EachPairAction = { notifier: NotifyProc = NARROW[val, NotifySet].activityOnNotify; IF notifier#NIL THEN notifier[key, enumeratedActivity, on]; }; IF procs#NIL THEN { wasOn ¬ procs.activityOn; procs.activityOn ¬ on; IF wasOn#on THEN { IF procs.activityProc#NIL THEN procs.activityProc[on, procs.activityProcData]; [] ¬ RefTab.Pairs[notificationTable, NotifyActivityOn]; }; }; }; wasOn ¬ FALSE; IF activity#NIL THEN [] ¬ SetActivity[activity, RefTab.Fetch[registrationTable, activity].val] ELSE [] ¬ RefTab.Pairs[registrationTable, SetActivity]; }; IsActivityOn: PUBLIC PROC [activity: ATOM] RETURNS [isOn: BOOLEAN] ~ { RETURN[NARROW[RefTab.Fetch[registrationTable, activity].val, ProcSet].activityOn]; }; NotificationRegister: PUBLIC PROC [handle: REF ANY, notifyProcs: NotifySet] RETURNS [] ~ { notifier: NotifyProc; NotifyAllRegister: RefTab.EachPairAction = { IF val#NIL THEN notifier[handle, NARROW[key], NARROW[val, ProcSet].activityOn]; }; [] ¬ RefTab.Store[notificationTable, handle, notifyProcs]; IF notifyProcs#NIL THEN { notifier ¬ notifyProcs.registrationNotify; IF notifier#NIL THEN [] ¬ RefTab.Pairs[registrationTable, NotifyAllRegister]; }; }; NotificationUnRegister: PUBLIC PROC [handle: REF ANY, doNotify: BOOLEAN ¬ FALSE] RETURNS [] ~ { notifier: NotifyProc; NotifyAllUnRegister: RefTab.EachPairAction = { IF val#NIL THEN notifier[handle, NARROW[key], NARROW[val, ProcSet].activityOn]; }; notifyProcs: NotifySet = NARROW[RefTab.Fetch[notificationTable, handle].val]; [] ¬ RefTab.Delete[notificationTable, handle]; IF doNotify AND notifyProcs#NIL THEN { notifier ¬ notifyProcs.unRegistrationNotify; IF notifier#NIL THEN [] ¬ RefTab.Pairs[registrationTable, NotifyAllUnRegister]; }; }; DoTransform: PUBLIC PROC [activity: ATOM, node: Node, parent: Node ¬ NIL, wantFirst: BOOL ¬ TRUE] RETURNS [new: Node] ~ { procs: ProcSet = NARROW[RefTab.Fetch[registrationTable, activity].val]; new ¬ IF procs=NIL OR NOT procs.activityOn OR procs.transformProc=NIL THEN node ELSE procs.transformProc[node, parent, wantFirst, procs.transformProcData]; }; GetSize: PUBLIC PROC [activity: ATOM, node: Node] RETURNS [size: INT] ~ { procs: ProcSet = NARROW[RefTab.Fetch[registrationTable, activity].val]; size ¬ IF procs=NIL OR NOT procs.activityOn OR procs.sizeProc=NIL THEN Rope.Size[node.rope] ELSE procs.sizeProc[node, procs.sizeProcData]; }; activeAtom: ATOM ~ NodeProps.nameActive; PTransform: PROC [node: Node, wantFirst: BOOL] RETURNS [Node] ~ { WITH NodeProps.GetProp[node, activeAtom] SELECT FROM activity: ROPE => RETURN[DoTransform[activity: Atom.MakeAtom[activity], node: node, parent: node.parent, wantFirst: wantFirst]]; ENDCASE => RETURN[node]; }; PSize: PROC [node: Node] RETURNS [INT] ~ { WITH NodeProps.GetProp[node, activeAtom] SELECT FROM activity: ROPE => RETURN[GetSize[activity: Atom.MakeAtom[activity], node: node]]; ENDCASE => RETURN[Rope.Size[node.rope]]; }; Transform: PROC [node: Node, wantFirst: BOOL ¬ TRUE] RETURNS [Node] ~ INLINE { RETURN[IF node#NIL AND node.hasActive THEN PTransform[node, wantFirst] ELSE node]; }; Size: PROC [node: Node] RETURNS [INT] ~ INLINE { RETURN[IF node.hasActive THEN PSize[node] ELSE Rope.Size[node.rope]]; }; NewTextNode: PUBLIC PROC RETURNS [Node] = { RETURN[NEW[Tioga.NodeRep ¬ []]]; }; XParent: PROC [n: Node] RETURNS [Node] ~ INLINE { RETURN[n.parent] }; XNext: PROC [n: Node] RETURNS [Node] ~ INLINE { RETURN[n.next] }; XChild: PROC [n: Node] RETURNS [Node] ~ INLINE { RETURN[n.child] }; XRoot: PROC [n: Node] RETURNS [root: Node ¬ NIL] ~ { FOR x: Node ¬ n, XParent[x] UNTIL x=NIL DO root ¬ x ENDLOOP; }; XFirstSibling: PROC [n: Node] RETURNS [Node] ~ { p: Node ~ XParent[n]; RETURN[IF p=NIL THEN n ELSE XChild[p]]; }; XPrevious: PROC [n: Node] RETURNS [prev: Node ¬ NIL] ~ { FOR x: Node ¬ XFirstSibling[n], XNext[x] UNTIL x=n DO prev ¬ x ENDLOOP; }; XForward: PROC [n: Node] RETURNS [nx: Node, deltaLevel: INTEGER] ~ { child: Node ~ XChild[n]; IF child#NIL THEN RETURN[child, 1] -- descend in the tree ELSE { -- move to sibling or up* then sibling x: Node ¬ n; FOR delta: INTEGER ¬ 0, delta-1 DO next: Node ~ XNext[x]; IF next#NIL THEN RETURN[next, delta]; -- the sibling IF (x ¬ XParent[x])=NIL THEN RETURN[NIL, delta]; -- the parent ENDLOOP; }; }; Parent: PUBLIC PROC [n: Node] RETURNS [Node] ~ { RETURN[IF n=NIL THEN NIL ELSE Transform[node: XParent[n], wantFirst: FALSE]]; }; Root: PUBLIC PROC [n: Node] RETURNS [Node] ~ { RETURN[IF n=NIL THEN NIL ELSE Transform[node: XRoot[n], wantFirst: TRUE]]; }; Level: PUBLIC PROC [n: Node] RETURNS [level: INTEGER ¬ 0] ~ { p: Node ¬ IF n=NIL THEN NIL ELSE XParent[n]; UNTIL p=NIL DO level ¬ level+1; p ¬ XParent[p] ENDLOOP; }; Next: PUBLIC PROC [n: Node] RETURNS [Node] ~ { RETURN[IF n=NIL THEN NIL ELSE Transform[node: XNext[n], wantFirst: TRUE]]; }; Previous: PUBLIC PROC [n: Node, parent: Node ¬ NIL] RETURNS [nx: Node] ~ { RETURN[IF n=NIL THEN NIL ELSE Transform[node: XPrevious[n], wantFirst: FALSE]]; }; FirstChild: PUBLIC PROC [n: Node] RETURNS [Node] ~ { RETURN[IF n=NIL THEN NIL ELSE Transform[node: XChild[n], wantFirst: TRUE]]; }; Forward: PUBLIC PROC [node: Node] RETURNS [nx: Node, levelDelta: INTEGER] ~ { IF node=NIL THEN RETURN[NIL, 0]; [nx, levelDelta] ¬ XForward[node]; nx ¬ Transform[node: nx, wantFirst: TRUE]; }; StepForward: PUBLIC PROC [node: Node] RETURNS [Node] ~ { RETURN[Forward[node].nx]; }; Backward: PUBLIC PROC [node: Node, parent: Node ¬ NIL] RETURNS [back, backparent: Node, levelDelta: INTEGER] = { child, child2: Node; IF node=NIL OR (parent ¬ XParent[node])=NIL THEN RETURN [NIL, NIL, 0]; IF (child ¬ parent.child) = node THEN RETURN [Transform[node: parent, wantFirst: FALSE], Parent[parent], -1]; DO IF child.next=NIL THEN ERROR; -- incorrect value supplied for parent IF (child2 ¬ child.next)=node THEN EXIT; child ¬ child2; ENDLOOP; levelDelta ¬ 0; child ¬ Transform[node: child, wantFirst: FALSE]; DO IF (child2 ¬ LastChild[child]) = NIL THEN RETURN [child, parent, levelDelta]; levelDelta ¬ levelDelta+1; parent ¬ child; child ¬ child2; ENDLOOP; }; StepBackward: PUBLIC PROC [node: Node, parent: Node ¬ NIL] RETURNS [Node] ~ { RETURN[Backward[node, parent].back]; }; ForwardClipped: PUBLIC PROC [node: Node, maxLevel: INTEGER, nodeLevel: INTEGER ¬ 0] RETURNS [nx: Node, nxLevel: INTEGER] = { child: Node; IF node=NIL THEN RETURN [NIL, 0]; IF nodeLevel <= 0 THEN nodeLevel ¬ Level[node]; IF nodeLevel < maxLevel AND (child ¬ node.child) # NIL THEN RETURN [Transform[node: child, wantFirst: TRUE], nodeLevel+1]; -- return the child DO -- move to next node, sibling or up* then sibling IF node.next#NIL THEN RETURN [Transform[node: node.next, wantFirst: TRUE], nodeLevel]; -- return the sibling IF (node ¬ node.parent) = NIL THEN RETURN [NIL, 0]; -- go to the parent nodeLevel ¬ nodeLevel-1; ENDLOOP; }; BackwardClipped: PUBLIC PROC [node: Node, maxLevel: INTEGER, parent: Node ¬ NIL, nodeLevel: INTEGER ¬ 0] RETURNS [back, backparent: Node, backLevel: INTEGER] = { child, child2: Node; IF node=NIL OR (parent ¬ XParent[node])=NIL THEN RETURN [NIL, NIL, 0]; IF nodeLevel <= 0 THEN nodeLevel ¬ Level[node]; IF (child ¬ parent.child) = node THEN RETURN [Transform[node: parent, wantFirst: FALSE], Parent[parent], nodeLevel-1]; DO -- search for sibling just before node IF child.next=NIL THEN ERROR; -- incorrect value supplied for parent IF (child2 ¬ child.next)=node THEN EXIT; child ¬ child2; ENDLOOP; child ¬ Transform[node: child, wantFirst: FALSE]; DO -- go deeper in tree until reach maxLevel IF nodeLevel >= maxLevel OR (child2 ¬ LastChild[child]) = NIL THEN RETURN [child, parent, nodeLevel]; nodeLevel ¬ nodeLevel+1; parent ¬ child; child ¬ child2; ENDLOOP; }; XLocRelative: PROC [location: Location, count: INT, break: NAT ¬ 1, skipCommentNodes: BOOL ¬ FALSE] RETURNS [Location] ~ { rem: INT ¬ MAX[count, 0]; last: Location ¬ [NIL, 0]; FOR node: Node _ location.node, XForward[node].nx UNTIL node=NIL DO IF NOT (skipCommentNodes AND node.comment) THEN { size: INT ~ Size[node]; start: INT ~ IF node=location.node THEN MIN[MAX[location.where, 0], size] ELSE 0; len: INT ~ size-start; IF rem<=len THEN RETURN[[node, start+rem]]; rem ¬ rem-MIN[len+break, rem]; last ¬ [node, size]; }; ENDLOOP; RETURN[last]; }; LocRelative: PUBLIC PROC [location: Location, count: INT, break: NAT ¬ 1, skipCommentNodes: BOOL ¬ FALSE] RETURNS [Location] ~ { loc: Location ~ XLocRelative[location, count, break, skipCommentNodes]; RETURN[[Transform[node: loc.node, wantFirst: TRUE], loc.where]]; }; LocWithin: PUBLIC PROC [n: Node, count: INT, break: NAT ¬ 1, skipCommentNodes: BOOL ¬ FALSE] RETURNS [Location] ~ { RETURN[LocRelative[[n, 0], count, break, skipCommentNodes]]; }; BadArgs: PUBLIC ERROR ~ CODE; LocOffset: PUBLIC PROC [loc1, loc2: Location, break: NAT ¬ 1, skipCommentNodes: BOOL ¬ FALSE] RETURNS [count: INT ¬ 0] ~ { FOR node: Node _ loc1.node, XForward[node].nx UNTIL node=NIL DO IF NOT (skipCommentNodes AND node.comment) THEN { size: INT ~ Size[node]; i0: INT ~ IF node=loc1.node THEN MIN[MAX[loc1.where, 0], size] ELSE 0; i1: INT ~ IF node=loc2.node THEN MIN[MAX[loc2.where, 0], size] ELSE size+break; count ¬ count+(i1-i0); }; IF node=loc2.node THEN RETURN; ENDLOOP; IF loc2.node#NIL THEN ERROR BadArgs; }; LocNumber: PUBLIC PROC [at: Location, break: NAT ¬ 1, skipCommentNodes: BOOL ¬ FALSE] RETURNS [count: INT] ~ { RETURN[LocOffset[[Root[at.node], 0], at, break, skipCommentNodes]]; }; FirstSibling: PUBLIC PROC [n: Node] RETURNS [Node] = { RETURN[FirstChild[Parent[n]]]; }; LastSibling: PUBLIC PROC [n: Node] RETURNS [Node] = { IF n=NIL THEN RETURN [NIL]; UNTIL n.next=NIL DO n ¬ n.next ENDLOOP; RETURN[Transform[node: n, wantFirst: FALSE]]; }; LastChild: PUBLIC PROC [n: Node] RETURNS [Node] = { RETURN[LastSibling[FirstChild[n]]]; }; LastWithin: PUBLIC PROC [n: Node] RETURNS [Node] = { nxt: Node; IF n=NIL THEN RETURN [NIL]; IF (nxt ¬ n.child)=NIL THEN RETURN [n]; n ¬ nxt; DO -- keep going to child of last sibling IF n.next=NIL THEN { IF (nxt ¬ n.child)=NIL THEN RETURN [Transform[node: n, wantFirst: FALSE]]; n ¬ nxt } ELSE n ¬ n.next; ENDLOOP; }; LastLocWithin: PUBLIC PROC [n: Node] RETURNS [Location] = { last: Node ¬ LastWithin[n]; where: INT ¬ IF last # NIL THEN Rope.Size[last.rope] ELSE Tioga.NodeItself; RETURN [[last, where]]; }; NthChild: PUBLIC PROC [n: Node, location: INT ¬ 0] RETURNS [child: Node] = { IF n=NIL OR (child ¬ n.child)=NIL THEN RETURN; DO IF location=0 THEN RETURN [Transform[node: child, wantFirst: TRUE]]; child ¬ Transform[node: child, wantFirst: TRUE]; IF child.next=NIL THEN RETURN [NIL]; child ¬ child.next; location ¬ location-1; ENDLOOP; }; NthSibling: PUBLIC PROC [n: Node, cnt: INT ¬ 0] RETURNS [Node] = { IF n=NIL THEN RETURN [NIL]; DO IF cnt=0 THEN RETURN [Transform[node: n, wantFirst: TRUE]]; n ¬ Transform[node: n, wantFirst: TRUE]; IF n.next=NIL THEN RETURN [NIL]; n ¬ n.next; cnt ¬ cnt-1; ENDLOOP; }; CountChildren: PUBLIC PROC [n: Node] RETURNS [count: INT ¬ 0] = { child: Node; IF (child ¬ FirstChild[n])=NIL THEN RETURN; DO count ¬ count+1; child ¬ Transform[node: child, wantFirst: TRUE]; IF child.next=NIL THEN RETURN; child ¬ child.next; ENDLOOP; }; CountFollowing: PUBLIC PROC [n: Node] RETURNS [count: INT ¬ 0] = { IF n=NIL THEN RETURN; UNTIL n.next=NIL DO n ¬ n.next; count ¬ count+1; n ¬ Transform[node: n, wantFirst: TRUE]; ENDLOOP; }; CountToParent: PUBLIC PROC [n: Node] RETURNS [count: INT ¬ 0, parent: Node] = { IF n=NIL THEN RETURN; UNTIL n.next=NIL DO n ¬ n.next; count ¬ count+1; n ¬ Transform[node: n, wantFirst: TRUE]; ENDLOOP; parent ¬ n.next; parent ¬ Transform[node: parent, wantFirst: FALSE]; }; CountToChild: PUBLIC PROC [parent, child: Node] RETURNS [count: INT ¬ 0] = { n: Node; IF parent=NIL OR child=NIL THEN RETURN; n ¬ Transform[node: parent.child, wantFirst: TRUE]; DO SELECT n FROM child => RETURN [count]; NIL => RETURN [TextNode.MaxLen]; ENDCASE; n ¬ Next[n]; count ¬ count+1; ENDLOOP; }; EndPos: PUBLIC PROC [n: Node] RETURNS [INT] = { IF n=NIL THEN RETURN [0]; RETURN [MAX[Rope.Size[n.rope], 1]-1]; }; DestroyTree: PUBLIC PROC [root: Node] ~ { parent: Node ~ Parent[root]; next: Node ¬ root; UNTIL next=parent DO -- go through the tree zapping REF's node: Node ~ next; IF node.child#NIL THEN { next ¬ node.child; node.child ¬ NIL } ELSE { next ¬ IF node.next#NIL THEN node.next ELSE node.parent; node.deleted ¬ TRUE; node.parent ¬ NIL; node.next ¬ NIL; node.rope ¬ NIL; node.runs ¬ NIL; node.charSets ¬ NIL; node.charProps ¬ NIL; node.nodeProps ¬ NIL; }; ENDLOOP; }; END. Œ TextNodeImpl.mesa Copyright Σ 1985, 1986, 1987, 1988, 1991, 1992 by Xerox Corporation. All rights reserved. written by Bill Paxton, March 1981 last edit by Bill Paxton, August 11, 1982 9:51 am Rick Beach, March 27, 1985 10:13:12 am PST Michael Plass, September 24, 1991 2:21 pm PDT Doug Terry, August 9, 1988 3:28:42 pm PDT Don Baker, June 3, 1988 4:24:24 pm PDT Bier, January 6, 1989 5:14:03 pm PST Doug Wyatt, July 21, 1992 4:37 pm PDT This is a modified version (by Doug Terry) of TextNodeImpl.mesa that performs transformations on "active" nodes as they are requested. Active nodes as those with the "Active" property; the value associated with this property identifies a particular transformation. Transformations must be registered using TextNodeRegistry. Note: All of the public procedures in this module assume that any nodes passed as inputs are regular text nodes (i.e. do not need to be transformed) and ensure that any nodes returned as results are regular text nodes. Strange behavior might result if the transformation of an active node yields another active node. TextNodeRegistryImpl The given TransformProc will hereafter be applied to all nodes having an active property with value=activity. Notification procedures are invoked accordingly. [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL _ FALSE] Removes the procedures associated with the given activity. Notification procedures are invoked accordingly. [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL _ FALSE] Return the procedures associated with the given activity. Determines whether or not the registered transformations should be currently applied; if activity=NIL then activity is turned on/off for all registered clients. Registered clients are informed via callbacks when this switch is toggled so they can take appropriate action. [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL _ FALSE] [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL _ FALSE] Returns true if the activity specified is on. Registers a set of notification procedures which are called both in the event of a change in activity registration or status *and* during this call, notification will be given of the "registration" of those activities which are already registered. [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL _ FALSE] Unregisters a set of notification procedures. If doNotify is set, notification of "unregistration" of registered activities will be made--during this call. [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL _ FALSE] Force the TransformProc associated with the given activity to be applied to the node. (This is intended primarily for use by TextNodeImpl.) Computes or estimates the size that the given node will be AFTER it is transformed by the specified activity. (This is intended primarily for use by TextNodeImpl.) Routines to check for and generate registered activities The rest of TextNodeImpl returns preceding node in standard tree walk order like Forward, but limits how deep will go in tree if pass nodeLevel=0, correct value will be computed nxLevel = Level[nx] <= MAX[maxLevel, Level[node]] like Backward, but limits how deep will go in tree backLevel = Level[back] <= MAX[maxLevel, Level[node]] note: NthChild[n, 0]==FirstChild[n]; NthChild[n, k+1]==Next[NthChild[n, k]] note: NthSibling[n, 0]==n; NthSibling[n, k+1]==Next[NthSibling[n, k]] note: CountToChild[parent, FirstChild[parent]]==0 Κb–(cedarcode) style•NewlineDelimiter ™code™Kšœ ΟeœO™ZKšœ"™"Kšœ1™1K™*Kšœ-™-K™)Kšœ&™&K™$K™%K™KšœΕ™ΕK™KšΟbœΊ™ΎK™—šΟk ˜ KšœŸœ ˜Kšœ Ÿœ˜&KšœŸœ<˜HKšœŸœŸœ ˜Kšœ ˜ KšœŸœ"˜8K˜—K˜KšΟn œŸœŸ˜KšŸœ˜%KšŸœ˜"šœŸ˜K˜KšœŸœ˜Kšœ Ÿœ˜ KšŸœŸœŸœ˜K˜—™K˜Kšœ Ÿœ˜)Kšœ Ÿœ˜-Kšœ Ÿœ˜/K˜Kšœ0˜0K˜0K˜š  œŸœŸœ ŸœŸœ˜EKšœŸ™Ÿš œ˜-Kšœ#ŸœŸœŸœ™?šŸœŸœŸœ˜KšœŸœ$˜AKšŸœ ŸœŸœ+˜?K˜—K˜—Kšœ6˜6K˜9K˜K™—š   œŸœŸœ ŸœŸœ˜7K™lKšœŸœ˜%š œ˜/Kšœ#ŸœŸœŸœ™?šŸœŸœŸœ˜KšœŸœ&˜CKšŸœ ŸœŸœ˜1K˜—K˜—K˜;Kšœ0˜0K˜K™—š  œŸœŸœ ŸœŸœ˜CJšœ9™9KšŸœŸœ1˜>K˜J™—š  œŸœŸœ ŸœŸœŸœŸœ Ÿœ˜SKšœbŸœ«™•StartOfExpansionC -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL _ FALSE]š  œ˜&Kšœ#ŸœŸœŸœ™?KšœŸœŸœ˜'KšœŸœ˜š œ˜+Kšœ#ŸœŸœŸœ™?KšœŸœ"˜?KšŸœ ŸœŸœ'˜;Kšœ˜—šŸœŸœŸœ˜Kšœ˜Kšœ˜šŸœ Ÿœ˜šŸœŸœŸ˜Kšœ/˜/—Kšœ7˜7K˜—K˜—K˜—KšœŸœ˜šŸœ Ÿ˜KšŸœJ˜NKšŸœ3˜7—K˜K˜—š   œŸœŸœ ŸœŸœŸœ˜FKšœ-™-KšŸœŸœE˜RK˜K˜—š  œŸœŸœ ŸœŸœŸœ˜ZK™χK˜š œ˜,Kšœ#ŸœŸœŸœ™?Kš ŸœŸœŸœŸœŸœ˜OK˜—K˜:šŸœ ŸœŸœ˜K˜*KšŸœ ŸœŸœ9˜MK˜—K˜K˜—š œŸœŸœ ŸœŸœ ŸœŸœŸœ˜_Kšœ‰Οc™œK˜š œ˜.Kšœ#ŸœŸœŸœ™?Kš ŸœŸœŸœŸœŸœ˜OK˜—KšœŸœ.˜MK˜/šŸœ Ÿœ ŸœŸœ˜&Kšœ,˜,KšŸœ ŸœŸœ;˜OK˜—K˜K™—š  œŸœŸœ ŸœŸœ ŸœŸœŸœ˜yKšœŒ™ŒKšœŸœ0˜GKšœŸœŸœŸœŸœŸœŸœŸœŸœG˜›K˜K™—š  œŸœŸœ Ÿœ ŸœŸœ˜IKšœ€™€KšœŸœ0˜GKšœŸœŸœŸœŸœŸœŸœŸœŸœ*˜ŠK˜K˜—K™—™8K˜šœ Ÿœ˜(K˜—š  œŸœŸœŸœ ˜AšŸœ%ŸœŸ˜4Kšœ ŸœŸœi˜KšŸœŸœ˜—K˜K˜—š œŸœŸœŸœ˜*šŸœ%ŸœŸ˜4Kšœ ŸœŸœ9˜QKšŸœŸœ˜(—K˜K˜—š   œŸœŸœŸœŸœ Ÿœ˜NKš ŸœŸœŸœŸœŸœŸœ˜RK˜K˜—š  œŸœŸœŸœŸœ˜0KšŸœŸœŸœ Ÿœ˜EK˜K˜—K˜—™K™š  œŸœŸœŸœ ˜+KšŸœŸœ˜ K˜K™—š  œŸœ Ÿœ ŸœŸœ ˜EK˜—š  œŸœ Ÿœ ŸœŸœ ˜AK˜—š  œŸœ Ÿœ ŸœŸœ ˜CK™—š œŸœ ŸœŸœ˜5Kš ŸœŸœŸœŸœ Ÿœ˜KšŸœ˜—K˜——K˜K˜—š œŸœŸœ Ÿœ ˜0KšŸœŸœŸœŸœŸœŸœ(Ÿœ˜MK˜K™—š œŸœŸœ Ÿœ ˜/KšŸœŸœŸœŸœŸœŸœ&Ÿœ˜JK˜—K˜š  œŸœŸœ Ÿœ Ÿœ ˜=Kš œ ŸœŸœŸœŸœŸœ ˜,KšŸœŸœŸœ!Ÿœ˜7K˜K˜—š œŸœŸœ Ÿœ ˜.KšŸœŸœŸœŸœŸœŸœ&Ÿœ˜JK˜—K˜š  œŸœŸœŸœŸœ˜JKšŸœŸœŸœŸœŸœŸœ*Ÿœ˜OK˜K™—š  œŸœŸœ Ÿœ ˜4KšŸœŸœŸœŸœŸœŸœ'Ÿœ˜KK˜K™—š  œŸœŸœŸœŸœ˜MKš ŸœŸœŸœŸœŸœ˜ K˜"Kšœ$Ÿœ˜*K˜K™—š  œŸœŸœŸœ ˜8KšŸœ˜K˜K˜—š œŸœŸœŸœ˜6KšŸœ&Ÿœ˜9K™2Kšœ˜KšŸœŸœŸœŸœŸœŸœŸœŸœ˜FKšŸœŸœŸœ%Ÿœ˜mš ŸœŸœ ŸœŸœŸœ‘&˜GKšŸœŸœŸœ˜(K˜KšŸœ˜—K˜Kšœ*Ÿœ˜1š ŸœŸœŸœŸœŸœ˜PK˜Kšœ˜KšŸœ˜—K˜K™—š   œŸœŸœŸœŸœ ˜MKšŸœ˜$K˜K˜—š œŸœŸœŸœŸœŸœŸœ˜~Kšœ1™1Kšœ4™4Kšœ1™1Kšœ ˜ Kš ŸœŸœŸœŸœŸœ˜!KšŸœŸœ˜/šŸœŸœŸœŸ˜;KšŸœ$Ÿœ‘˜R—šŸœ‘œ‘˜4Kš Ÿœ ŸœŸœŸœ(Ÿœ‘˜lKš ŸœŸœŸœŸœŸœ‘˜GK˜KšŸœ˜—K˜—K˜š œŸœŸœŸœŸœ ŸœŸœ%Ÿœ˜£Kšœ2™2Kšœ5™5Kšœ˜KšŸœŸœŸœŸœŸœŸœŸœŸœ˜FKšŸœŸœ˜/KšŸœŸœŸœ%Ÿœ ˜všŸœ‘&˜)Kš Ÿœ ŸœŸœŸœ‘&˜DKšŸœŸœŸœ˜(K˜KšŸœ˜—Kšœ*Ÿœ˜1šŸœ‘)˜,KšŸœŸœŸœŸ˜BKšŸœ˜"K˜K˜K˜KšŸœ˜—K˜—K˜š   œŸœŸœ ŸœŸœŸœŸœ˜{KšœŸœŸœ ˜KšœŸœ˜šŸœ/ŸœŸœŸ˜CšŸœŸœŸœŸœ˜1KšœŸœ˜Kš œŸœŸœŸœŸœŸœŸœ˜QKšœŸœ˜KšŸœ ŸœŸœ˜+Kšœ Ÿœ˜K˜K˜—KšŸœ˜—KšŸœ˜ K˜K™—š  œŸœŸœŸœ ŸœŸœŸœŸœ˜K˜GKšŸœ'Ÿœ˜@K˜K™—š  œŸœŸœŸœ ŸœŸœŸœŸœ˜tKšŸœ6˜Kšœ"Ÿœ˜(Kš ŸœŸœŸœŸœŸœ˜ K˜ Kšœ ˜ KšŸœ˜—K˜—K˜š   œŸœŸœ Ÿœ Ÿœ ˜AKšœ ˜ KšŸœŸœŸœŸœ˜+šŸœ˜Kšœ*Ÿœ˜0KšŸœ ŸœŸœŸœ˜K˜KšŸœ˜—K˜—K˜š  œŸœŸœ Ÿœ Ÿœ ˜BKšŸœŸœŸœŸœ˜šŸœŸœŸ˜K˜ K˜Kšœ"Ÿœ˜(KšŸœ˜—K˜—K˜š   œŸœŸœ Ÿœ Ÿœ˜OKšŸœŸœŸœŸœ˜šŸœŸœŸ˜K˜ K˜Kšœ"Ÿœ˜(KšŸœ˜—K˜Kšœ,Ÿœ˜3K˜—K˜š   œŸœŸœŸœ Ÿœ ˜LKšœ1™1Kšœ˜Kš ŸœŸœŸœŸœŸœŸœ˜'Kšœ-Ÿœ˜3šŸœŸœŸ˜Kšœ Ÿœ ˜KšŸœŸœ˜ KšŸœ˜Kšœ ˜ K˜KšŸœ˜—K˜K™—K˜š  œŸœŸœ ŸœŸœ˜/KšŸœŸœŸœŸœ˜KšŸœŸœ˜%K˜K˜—K™š  œŸœŸœ˜)K˜Kšœ˜šŸœ Ÿœ‘$˜9K˜KšŸœ ŸœŸœ#Ÿœ˜>šŸœ˜Kš œŸœ ŸœŸœ Ÿœ ˜8KšœŸœ˜KšœŸœ˜Kšœ Ÿœ˜Kšœ Ÿœ˜Kšœ Ÿœ˜KšœŸœ˜KšœŸœ˜KšœŸœ˜K˜—KšŸœ˜—K˜K™——K˜KšŸœ˜—…—7Δ[²