DIRECTORY Atom, Basics, Collections, PairCollections, List, Process; PairCollectionsImpl: CEDAR MONITOR LOCKS par USING par: Parallel IMPORTS Atom, Collections, PairCollections, List, Process EXPORTS PairCollections = BEGIN OPEN Colls:Collections, Collections, PairCollections; Cant: PUBLIC ERROR [pc: PairColl] ~ CODE; Cons: PUBLIC PROC [class: PairCollClass, data: REF ANY] RETURNS [PairColl] ~ { RETURN [[class, data]]}; notNew: PUBLIC ROPE ~ BeRope["function %g already had mapping for domain of %g"]; noPair: PUBLIC Pair ~ [Collections.noValue, Collections.noValue]; noMaybePair: PUBLIC MaybePair ~ [FALSE, noPair]; Escape: ERROR = CODE; provisionKey: ATOM ~ $PairCollectionsImplProvision; bkwdableKey: ATOM ~ $PairCollectionsImplBkwdable; dirableKey: ATOM ~ $PairCollectionsImplDirable; kindKey: ATOM ~ $PairCollectionsImplKind; CreateClass: PUBLIC PROC [cp: PairCollClassPrivate, bkwdable: BB _ [TRUE, FALSE], dirable: BoolPair _ [TRUE, FALSE]] RETURNS [class: PairCollClass] ~ { provs: Atom.PropList _ NARROW[List.Assoc[key: provisionKey, aList: cp.other]]; Sp: PROC [op: ATOM, def: BOOL] RETURNS [BOOL] ~ { provs _ List.PutAssoc[op, IF def THEN $Default ELSE $Primitive, provs]; RETURN [def]}; {OPEN cp; IF Sp[$Widen, Widen=NIL] THEN Widen _ DefaultWiden; IF Sp[$HasPair, HasPair=NIL] THEN HasPair _ DefaultHasPair; IF Sp[$Image, Image=NIL] THEN Image _ DefaultImage; IF Sp[$Apply, Apply=NIL] THEN Apply _ DefaultApply; IF Sp[$Scan, Scan=NIL] THEN Scan _ DefaultScan; IF Sp[$ScanHalfRestriction, ScanHalfRestriction=NIL] THEN ScanHalfRestriction _ DefaultScanHalfRestriction; IF Sp[$Extremum, Extremum=NIL] THEN Extremum _ DefaultExtremum; IF Sp[$Get3, Get3=NIL] THEN Get3 _ DefaultGet3; IF Sp[$Size, Size=NIL] THEN Size _ DefaultSize; IF Sp[$ImageSize, ImageSize=NIL] THEN ImageSize _ DefaultImageSize; IF Sp[$Copy, Copy=NIL] THEN Copy _ DefaultCopy; IF Sp[$Insulate, Insulate=NIL] THEN Insulate _ DefaultInsulate; IF Sp[$ValueOf, ValueOf=NIL] THEN ValueOf _ DefaultValueOf; IF Sp[$Freeze, Freeze=NIL] THEN Freeze _ DefaultFreeze; IF Sp[$Thaw, Thaw=NIL] THEN Thaw _ DefaultThaw; IF Sp[$CollectionOn, CollectionOn=NIL] THEN CollectionOn _ DefaultCollectionOn; IF Sp[$CurSetOn, CurSetOn=NIL] THEN CurSetOn _ DefaultCurSetOn; IF Sp[$AddColl, AddColl=NIL] THEN AddColl _ DefaultAddColl; IF Sp[$RemColl, RemColl=NIL] THEN RemColl _ DefaultRemColl; IF Sp[$DeleteColl, DeleteColl=NIL] THEN DeleteColl _ DefaultDeleteColl; IF Sp[$QuaIntFn, QuaIntFn=NIL] THEN QuaIntFn _ DefaultQuaIntFn; IF Sp[$OrderingOf, OrderingOf=NIL] THEN OrderingOf _ DefaultOrderingOf; }; cp.other _ List.PutAssoc[provisionKey, provs, cp.other]; cp.other _ List.PutAssoc[bkwdableKey, NEW [BB _ bkwdable], cp.other]; cp.other _ List.PutAssoc[dirableKey, NEW [BoolPair _ dirable], cp.other]; class _ NEW [PairCollClassPrivate _ cp]; }; Primitive: PROC [pc: PairColl, op: ATOM, args: ArgList _ NIL] RETURNS [BOOL] ~ { kind: REF ANY ~ Atom.GetProp[atom: op, prop: kindKey]; SELECT kind FROM $class, $classD, $classB, $classBR, $classSB, $classS => NULL; ENDCASE => ERROR; IF pc.class.Primitive # NIL THEN SELECT pc.class.Primitive[pc, op, args] FROM yes => RETURN [TRUE]; no => RETURN [FALSE]; pass => NULL; ENDCASE => ERROR; {provs: Atom.PropList ~ NARROW[List.Assoc[key: provisionKey, aList: pc.class.other]]; prov: REF ANY ~ List.Assoc[op, provs]; bkwdable: REF BB ~ NARROW[List.Assoc[bkwdableKey, pc.class.other]]; dirable: REF BoolPair ~ NARROW[List.Assoc[dirableKey, pc.class.other]]; RETURN [SELECT prov FROM $Default => FALSE, $Primitive => SELECT kind FROM $class => TRUE, $classD => dirable[GetDir[args, 1]], $classB => bkwdable[GetBool[args, 1]], $classBR => (pc.MutabilityOf[]#variable AND GetBool[args, 2]) OR bkwdable[GetBool[args, 1]], $classSB => dirable[From[GetSide[args, 1]]] AND bkwdable[GetBool[args, 2]], $classS => dirable[From[GetSide[args, 1]]], ENDCASE => ERROR, ENDCASE => ERROR]; }}; QualityOf: PUBLIC PROC [pc: PairColl, op: ATOM, args: ArgList _ NIL] RETURNS [ImplQuality] ~ { SELECT Atom.GetProp[atom: op, prop: kindKey] FROM $class, $classD, $classB, $classBR, $classSB, $classS => NULL; $composite => SELECT op FROM $Mapping => RETURN QualityOf[pc, $Image, args]; $Enumerate => RETURN QualityOf[pc, $Scan, args]; $EnumerateImage => RETURN QualityOf[pc, $ScanImage, args]; $EnumerateMapping => RETURN QualityOf[pc, $ScanImage, args]; $EnumerateHalfRestriction => RETURN QualityOf[pc, $ScanHalfRestriction, args]; $ScanImage => RETURN QualityOf[pc, $ScanHalfRestriction, IF args#NIL THEN CONS[FromSide[Source[GetDir[args, 1]]], args.rest] ELSE NIL]; $ScanMapping => RETURN QualityOf[pc, $ScanImage, args]; $First => RETURN QualityOf[pc, $Extremum, LIST[$FALSE, $FALSE]]; $Last => RETURN QualityOf[pc, $Extremum, LIST[$TRUE, $FALSE]]; $Pop => RETURN QualityOf[pc, $Extremum, LIST[FromBool[GetBool[args, 1]], $TRUE]]; $Next => RETURN QMin[QualityOf[pc, $Get3], goodDefault]; $Prev => RETURN QMin[QualityOf[pc, $Get3], goodDefault]; $Empty => RETURN [SELECT QualityOf[pc, $Size, args] FROM primitive => primitive, goodDefault, poorDefault => goodDefault, cant => cant, ENDCASE => ERROR]; $MappingSize => RETURN QualityOf[pc, $ImageSize, args]; $AddPair => RETURN QualityOf[pc, $AddColl, args]; $Store => RETURN QualityOf[pc, $AddColl, args]; $Replace => RETURN QualityOf[pc, $AddColl, args]; $Insert => RETURN QualityOf[pc, $AddColl, args]; $Inserted => RETURN QualityOf[pc, $AddColl, args]; $RemPair => RETURN QualityOf[pc, $RemColl, args]; $Delete => RETURN QualityOf[pc, $DeleteColl, args]; $IsIntFn => RETURN QualityOf[pc, $QuaIntFn, args]; $AsIntFn => RETURN QualityOf[pc, $QuaIntFn, args]; ENDCASE => ERROR; ENDCASE => ERROR; IF Primitive[pc, op, args] THEN RETURN [primitive]; RETURN [SELECT op FROM $Widen => cant, $HasPair => IF pc.Functional[][leftToRight] AND Primitive[pc, $Apply, LIST[$leftToRight]] OR pc.Functional[][rightToLeft] AND Primitive[pc, $Apply, LIST[$rightToLeft]] THEN goodDefault ELSE IF pc.Spaces[][left]#NIL AND pc.Spaces[][right]#NIL THEN poorDefault ELSE cant, $Image => QMin[poorDefault, QualityOf[pc, $Enumerate]], $Apply => QMin[goodDefault, QualityOf[pc, $Mapping, args]], $Scan => IF Primitive[pc, $Scan, LIST[FromBool[NOT GetBool[args, 1]]]] THEN poorDefault ELSE cant, $ScanHalfRestriction => QMax[ QMin[QualityOf[pc, $Image, LIST[FromDir[From[GetSide[args, 1]]]]], goodDefault], QMin[QualityOf[pc, $Scan, LIST[FromBool[GetBool[args, 2]]]], poorDefault]], $Extremum => QMin[IF pc.QualityOf[$Scan, args] >= goodDefault THEN goodDefault ELSE poorDefault, IF GetBool[args, 2] THEN pc.QualityOf[$RemPair] ELSE goodDefault], $Get3 => IF QualityOf[pc, $Spaces]=cant THEN cant ELSE QMin[poorDefault, QMax[QualityOf[pc, $Scan, LIST[$TRUE]], QualityOf[pc, $Scan, LIST[$FALSE]]]], $Size => QMin[QualityOf[pc, $Scan], poorDefault], $ImageSize => QMin[QualityOf[pc, $ScanImage, args], poorDefault], $Copy => cant, $Insulate => goodDefault, $ValueOf => IF pc.class.mutability=constant THEN goodDefault ELSE QMin[poorDefault, QMin[QualityOf[pc, $Copy], QualityOf[pc, $Freeze]]], $Freeze, $Thaw => IF pc.MutabilityOf=variable THEN cant ELSE ERROR, $CollectionOn => QMin[QualityOf[pc, $Enumerate], poorDefault], $CurSetOn => IF pc.MutabilityOf=constant THEN QMin[goodDefault, QualityOf[pc, $CollectionOn, args]] ELSE cant, $AddColl, $RemoveColl, $DeleteColl => IF pc.MutabilityOf=variable THEN cant ELSE goodDefault, $QuaIntFn => goodDefault, $Spaces => cant, $OrderingOf => IF pc.class.orderStyle#value THEN goodDefault ELSE QMin[goodDefault, QualityOf[pc, $Spaces]], ENDCASE => ERROR]; }; DefaultHasPair: PUBLIC PROC [pc: PairColl, pair: Pair] RETURNS [has: BOOL] ~ { goal: Pair ~ pair; spaces: SpacePair ~ pc.Spaces[]; Has: PROC [pair: Pair] RETURNS [pass: BOOL _ FALSE] --Tester-- ~ { pass _ spaces[left].SpaceEqual[goal[left], pair[left]] AND spaces[right].SpaceEqual[goal[right], pair[right]]; }; IF pc.Functional[][leftToRight] AND Primitive[pc, $Apply, LIST[$leftToRight]] THEN {appl: MaybeValue ~ pc.Apply[pair[left], leftToRight]; has _ appl.found AND spaces[right].SpaceEqual[appl.val, pair[right]]} ELSE IF pc.Functional[][rightToLeft] AND Primitive[pc, $Apply, LIST[$rightToLeft]] THEN {appl: MaybeValue ~ pc.Apply[pair[right], rightToLeft]; has _ appl.found AND spaces[left].SpaceEqual[appl.val, pair[left]]} ELSE IF spaces[left]#NIL AND spaces[right]#NIL THEN has _ pc.Scan[Has].found ELSE Cant[pc]; RETURN}; DefaultImage: PUBLIC PROC [pc: PairColl, coll: Collection, dir: Direction] RETURNS [UWColl] ~ { ic: ImageColl ~ NEW [ImageCollPrivate _ [pc, coll, dir]]; RETURN Colls.CreateEnumerator[e: [EnumerateImageColl, pc.Spaces[][Dest[dir]], NIL, ic], mayDuplicate: FALSE].AsUW[]; }; ImageColl: TYPE ~ REF ImageCollPrivate; ImageCollPrivate: TYPE ~ RECORD [pc: PairColl, coll: Collection, dir: Direction]; EnumerateImageColl: PROC [Consume: PROC [val: Value], data: REF ANY _ NIL] ~ { ic: ImageColl ~ NARROW[data]; Pass: PROC [pair: Pair] RETURNS [pass: BOOL _ FALSE] ~ { Consume[pair[Dest[ic.dir]]]; RETURN}; TestAndPass: PROC [pair: Pair] RETURNS [pass: BOOL _ FALSE] ~ { IF ic.coll.HasMember[pair[Source[ic.dir]]] THEN Consume[pair[Dest[ic.dir]]]; RETURN}; IF Primitive[ic.pc, $ScanHalfRestriction, LIST[FromSide[Source[ic.dir]]]] THEN [] _ ic.pc.ScanHalfRestriction[ic.coll, Pass, Source[ic.dir]] ELSE [] _ ic.pc.Scan[TestAndPass]; RETURN}; DefaultApply: PUBLIC PROC [pc: PairColl, v: Value, dir: Direction] RETURNS [mv: MaybeValue _ noMaybe] ~ { IF NOT pc.Functional[][dir] THEN pc.Complain["%g not functional in this direction"]; {map: UWColl ~ pc.Mapping[v, dir]; SELECT map.Size[2] FROM 0 => RETURN; 1 => RETURN [[TRUE, map.TheElt[]]]; ENDCASE => ERROR; }}; Enumerate: PUBLIC PROC [pc: PairColl, Consume: PROC [pair: Pair], bkwd: BOOL _ FALSE] ~ { Pass: PROC [x: Pair] RETURNS [pass: BOOL _ FALSE] ~ {Consume[x]}; [] _ pc.Scan[Pass, bkwd]; RETURN}; DefaultScan: PUBLIC PROC [pc: PairColl, Test: Tester, bkwd: BOOL] RETURNS [mv: MaybePair _ noMaybePair] ~ { pl: BOOL ~ Primitive[pc, $ScanHalfRestriction, LIST[$left, FromBool[bkwd]]]; pr: BOOL ~ Primitive[pc, $ScanHalfRestriction, LIST[$right, FromBool[bkwd]]]; IF pl OR pr THEN { s: Side ~ IF NOT pl THEN right ELSE IF NOT pr THEN left ELSE IF pc.Functional[] = [FALSE, TRUE] THEN right ELSE left; mv _ pc.ScanHalfRestriction[passAll, Test, s, bkwd]; } ELSE IF Primitive[pc, $Scan, LIST[FromBool[NOT bkwd]]] THEN { elts: LOP _ NIL; Addit: PROC [x: Pair] ~ {elts _ CONS[x, elts]}; pc.Enumerate[Addit, NOT bkwd]; FOR elts _ elts, elts.rest WHILE elts # NIL DO IF Test[elts.first] THEN RETURN [[TRUE, elts.first]] ENDLOOP; } ELSE Cant[pc]; RETURN}; EnumerateImage: PUBLIC PROC [pc: PairColl, coll: Collection, Consume: PROC [v: Value], dir: Direction _ leftToRight, bkwd: BOOL _ FALSE] ~ { Pass: PROC [x: Pair] RETURNS [pass: BOOL _ FALSE] ~ {Consume[x[Dest[dir]]]}; [] _ pc.ScanHalfRestriction[coll, Pass, Source[dir], bkwd]; RETURN}; EnumerateHalfRestriction: PUBLIC PROC [pc: PairColl, coll: Collection, Consume: PROC [pair: Pair], side: Side _ left, bkwd: BOOL _ FALSE] ~ { Pass: PROC [pair: Pair] RETURNS [pass: BOOL _ FALSE] ~ {Consume[pair]}; [] _ pc.ScanHalfRestriction[coll, Pass, side, bkwd]; RETURN}; ScanImage: PUBLIC PROC [pc: PairColl, coll: Collection, Test: Colls.Tester, dir: Direction _ leftToRight, bkwd: BOOL _ FALSE] RETURNS [mp: MaybePair _ noMaybePair] ~ { Mid: PROC [pair: Pair] RETURNS [pass: BOOL _ FALSE] ~ {pass _ Test[pair[Dest[dir]]]}; mp _ pc.ScanHalfRestriction[coll, Mid, Source[dir], bkwd]; RETURN}; DefaultScanHalfRestriction: PUBLIC PROC [pc: PairColl, side: Side, coll: Collection, Test: Tester, bkwd: BOOL] RETURNS [MaybePair] ~ { ImageColl: PROC RETURNS [mp: MaybePair _ noMaybePair] ~ { PerDom: PROC [v: Value] RETURNS [pass: BOOL] ~ { image: Collection ~ pc.Mapping[v, From[side]]; pair: Pair _ ALL[v]; PerRange: PROC [w: Value] RETURNS [pass: BOOL] ~ { pair[OtherSide[side]] _ w; IF (pass _ Test[pair]) THEN mp _ [TRUE, pair]; RETURN}; pass _ image.Scan[PerRange, bkwd].found; RETURN}; [] _ coll.Scan[PerDom, bkwd]; RETURN}; ScanPC: PROC RETURNS [mp: MaybePair] ~ { PerPair: PROC [pair: Pair] RETURNS [pass: BOOL _ FALSE] ~ { pass _ coll.HasMember[pair[side]] AND Test[pair]; RETURN}; mp _ pc.Scan[PerPair, bkwd]; RETURN}; pcCanScan: BOOL ~ pc.Can[$Scan, LIST[FromBool[bkwd]]]; collCanScan: BOOL ~ coll.Can[$Scan, LIST[FromBool[bkwd]]]; pcGoodSize: BOOL ~ pc.QualityOf[$Size] >= goodDefault; collGoodSize: BOOL ~ coll.QualityOf[$Size] >= goodDefault; pcGoodImage: BOOL ~ pc.QualityOf[$Image] >= goodDefault; collGoodMemb: BOOL ~ coll.QualityOf[$HasMember] >= goodDefault; IF (NOT pcCanScan) AND (NOT collCanScan) THEN Cant[pc]; IF NOT pcCanScan THEN RETURN ImageColl[]; IF NOT collCanScan THEN RETURN ScanPC[]; IF pcGoodSize AND collGoodSize THEN RETURN (IF (IF coll.Size[] < pc.Size[] THEN pcGoodImage ELSE NOT collGoodMemb) THEN ImageColl ELSE ScanPC)[]; RETURN (IF pcGoodImage THEN ImageColl ELSE ScanPC)[]; }; DefaultExtremum: PUBLIC PROC [pc: PairColl, bkwd, remove: BOOL] RETURNS [m: MaybePair] ~ { Easy: PROC [val: Pair] RETURNS [pass: BOOL _ FALSE] ~ {pass _ TRUE}; Hard: PROC [val: Pair] RETURNS [pass: BOOL _ FALSE] ~ {m _ [TRUE, val]}; IF pc.QualityOf[$Scan, LIST[FromBool[bkwd]]] >= goodDefault THEN m _ pc.Scan[Easy, bkwd] ELSE [] _ pc.Scan[Hard, NOT bkwd]; IF m.found AND remove THEN { had: BoolPair ~ pc.RemPair[m.pair, IF bkwd THEN last ELSE first]; FOR dir: Direction IN Direction DO IF pc.Functional[][dir] AND NOT had[dir] THEN ERROR; ENDLOOP; }; RETURN}; DefaultGet3: PUBLIC PROC [pc: PairColl, pair: Pair] RETURNS [prev, same, next: MaybePair] ~ { fq: ImplQuality ~ pc.QualityOf[$Scan, LIST[$FALSE]]; bq: ImplQuality ~ pc.QualityOf[$Scan, LIST[$TRUE]]; bkwd: BOOL ~ bq > fq; take: BOOL _ FALSE; spaces: SpacePair ~ pc.Spaces[]; Pass: PROC [val: Pair] RETURNS [pass: BOOL _ FALSE] ~ { IF spaces[left].SpaceEqual[val[left], pair[left]] AND spaces[right].SpaceEqual[val[right], pair[right]] THEN same _ [take _ TRUE, pair] ELSE IF take THEN pass _ TRUE ELSE prev _ [TRUE, val]; }; IF spaces[left]=NIL OR spaces[right]=NIL THEN Cant[pc]; prev _ same _ noMaybePair; next _ pc.Scan[Pass, bkwd]; IF bkwd THEN RETURN [next, same, prev]; RETURN}; DefaultSize: PUBLIC PROC [pc: PairColl, limit: LNAT] RETURNS [size: LNAT] ~ { Pass: PROC [Pair] RETURNS [pass: BOOL] ~ {pass _ limit <= (size _ size+1)}; size _ 0; [] _ pc.Scan[Pass]; RETURN}; DefaultImageSize: PUBLIC PROC [pc: PairColl, coll: Collection, dir: Direction, limit: LNAT] RETURNS [size: LNAT] ~ { Pass: PROC [Value] RETURNS [pass: BOOL] ~ {pass _ limit <= (size _ size+1)}; size _ 0; [] _ pc.ScanImage[coll, Pass, dir]; RETURN}; DefaultCopy: PUBLIC PROC [pc: PairColl] RETURNS [VarPairColl] ~ {Cant[pc]}; DefaultValueOf: PUBLIC PROC [pc: PairColl] RETURNS [ConstPairColl] ~ {IF pc.class.mutability#constant THEN RETURN pc.Copy.Freeze[] ELSE RETURN AsConst[pc]}; DefaultFreeze: PROC [pc: PairColl] RETURNS [const: ConstPairColl] ~ {IF pc.MutabilityOf#variable THEN Complain[pc, notVariable] ELSE Cant[pc]}; DefaultThaw: PROC [pc: PairColl] ~ {IF pc.MutabilityOf#variable THEN Complain[pc, notVariable] ELSE Cant[pc]}; DefaultCollectionOn: PUBLIC PROC [pc: PairColl, side: Side] RETURNS [UWColl] ~ { coc: CollectionOnColl ~ NEW [CollectionOnCollPrivate _ [pc, side]]; mut: Mutability ~ SELECT pc.MutabilityOf FROM variable, readonly => readonly, constant => constant, ENDCASE => ERROR; RETURN Colls.CreateEnumerator[[EnumerateCollectionOn, pc.Spaces[][side], NIL, coc], pc.class.mayDuplicate OR NOT pc.class.functional[From[side]], none, mut].AsUW[]; }; CollectionOnColl: TYPE ~ REF CollectionOnCollPrivate; CollectionOnCollPrivate: TYPE ~ RECORD [pc: PairColl, side: Side]; EnumerateCollectionOn: PROC [Consume: PROC [val: Value], data: REF ANY _ NIL] ~ { coc: CollectionOnColl ~ NARROW[data]; Pass: PROC [pair: Pair] ~ {Consume[pair[coc.side]]}; coc.pc.Enumerate[Pass]; RETURN}; DefaultCurSetOn: PUBLIC PROC [pc: PairColl, side: Side] RETURNS [ConstSet] ~ { IF pc.MutabilityOf=constant THEN RETURN pc.CollectionOn[side].AsConst ELSE Cant[pc]; }; AddPair: PUBLIC PROC [pc: PairColl, pair: Pair, if: IfNewsPair _ ALL[ALL[TRUE]], where: Where _ []] RETURNS [news: NewsPair] ~ { some: NewsSetPair ~ pc.AddColl[CreateSingleton[pair, pc.Spaces], if, where]; news _ ALL[different]; FOR dir: Direction IN Direction DO IF pc.Functional[][dir] THEN news[dir] _ SELECT TRUE FROM some[dir][new] => new, some[dir][same] => same, some[dir][different] => different, ENDCASE => ERROR; ENDLOOP; RETURN}; AddNewPair: PUBLIC PROC [pc: PairColl, pair: Pair, where: Where _ []] ~ { some: NewsSetPair ~ pc.AddColl[CreateSingleton[pair, pc.Spaces], addIfNew, where]; FOR dir: Direction IN Direction DO IF pc.Functional[][dir] AND (some[dir][same] OR some[dir][different]) THEN ERROR; ENDLOOP; RETURN}; AddNewColl: PUBLIC PROC [pc, other: PairColl, where: Where _ []] ~ { some: NewsSetPair ~ AddColl[pc, other, addIfNew, where]; FOR dir: Direction IN Direction DO IF pc.Functional[][dir] AND (some[dir][same] OR some[dir][different]) THEN ERROR; ENDLOOP; RETURN}; DefaultAddColl: PUBLIC PROC [pc, other: PairColl, if: IfNewsPair, where: Where] RETURNS [some: NewsSetPair] ~ {IF pc.MutabilityOf#variable THEN Complain[pc, notVariable] ELSE Cant[pc]}; DefaultRemColl: PUBLIC PROC [pc, other: PairColl, style: RemoveStyle] RETURNS [hadSome, hadAll: BoolPair] ~ {IF pc.MutabilityOf#variable THEN Complain[pc, notVariable] ELSE Cant[pc]}; DefaultDeleteColl: PUBLIC PROC [pc: PairColl, coll: Collection, side: Side, style: RemoveStyle] RETURNS [hadSome, hadAll: BOOL] ~ {IF pc.MutabilityOf#variable THEN Complain[pc, notVariable] ELSE Cant[pc]}; DefaultSpaces: PUBLIC PROC [pc: PairColl] RETURNS [SpacePair] ~ {RETURN[[NIL, NIL]]}; DefaultOrderingOf: PUBLIC PROC [pc: PairColl] RETURNS [Ordering] ~ { IF pc.class.orderStyle#value THEN RETURN [unordered]; {spaces: SpacePair ~ pc.Spaces[]; IF spaces[left]=NIL OR spaces[right]=NIL OR spaces[left].Compare=CantCompare OR spaces[right].Compare=CantCompare THEN Cant[pc]; RETURN [[SpacesCompare, NEW [SpacePair _ spaces], both]]; }}; IsDefaultOrdering: PUBLIC PROC [o: Ordering] RETURNS [BOOL] ~ {RETURN [o.Compare=SpacesCompare]}; SpacesCompare: PROC [data: REF ANY, elt1, elt2: Pair] RETURNS [Basics.Comparison] ~ { spaces: REF SpacePair ~ NARROW[data]; c: Basics.Comparison _ spaces[left].SpaceCompare[elt1[left], elt1[left]]; IF c=equal THEN c _ spaces[right].SpaceCompare[elt1[right], elt1[right]]; RETURN[c]}; ParallelScanHalfRestriction: PUBLIC PROC [a, b: PairColl, coll: Collection, Test: ParallelTester, side: Side _ left, bkwd: BOOL _ FALSE] RETURNS [pf: ParallelFind] ~ TRUSTED { par: Parallel ~ NEW [ParallelPrivate _ [pc: [a, b] ]]; pa: PROCESS ~ FORK Par[par, a, coll, side, bkwd]; pb: PROCESS ~ FORK Par[par, b, coll, side, bkwd]; WaitForReq: ENTRY SAFE PROC [par: Parallel] RETURNS [continue: BOOL] ~ TRUSTED { ENABLE UNWIND => NULL; DO IF NOT par.ready[a] THEN {WAIT par.change; LOOP}; IF NOT par.ready[b] THEN {WAIT par.change; LOOP}; RETURN [par.pair[a].found OR par.pair[b].found]; ENDLOOP; }; Satisfy: ENTRY SAFE PROC [par: Parallel] ~ TRUSTED { ENABLE UNWIND => NULL; par.ready[a] _ par.ready[b] _ FALSE; BROADCAST par.change; RETURN}; pf _ [FALSE, noMaybePair, noMaybePair]; DO IF NOT WaitForReq[par] THEN EXIT; IF (par.pass _ Test[par.pair[a], par.pair[b]]) THEN pf _ [TRUE, par.pair[a], par.pair[b]]; Satisfy[par]; IF par.pass THEN EXIT; ENDLOOP; JOIN pa; JOIN pb; RETURN}; Which: TYPE ~ {a, b}; Parallel: TYPE ~ REF ParallelPrivate; ParallelPrivate: TYPE ~ MONITORED RECORD [ pc: ARRAY Which OF PairColl, ready: ARRAY Which OF BOOL _ ALL[FALSE], pass: BOOL _ FALSE, change: CONDITION _ [timeout: Process.SecondsToTicks[10]], pair: ARRAY Which OF MaybePair _ ALL[[TRUE, noPair]] ]; Par: PROC [par: Parallel, which: Which, coll: Collection, side: Side, bkwd: BOOL] ~ { Mediate: PROC [pair: Pair] RETURNS [pass: BOOL _ FALSE] ~ { WithLock: ENTRY PROC [par: Parallel] ~ { ENABLE UNWIND => NULL; par.pair[which].pair _ pair; par.ready[which] _ TRUE; BROADCAST par.change; UNTIL NOT par.ready[which] DO WAIT par.change ENDLOOP; pass _ par.pass; RETURN}; WithLock[par]; RETURN}; Finish: ENTRY PROC [par: Parallel] ~ { ENABLE UNWIND => NULL; par.pair[which].found _ FALSE; par.ready[which] _ TRUE; BROADCAST par.change; RETURN}; IF coll=passAll THEN [] _ par.pc[which].Scan[Mediate, bkwd] ELSE [] _ par.pc[which].ScanHalfRestriction[coll, Mediate, side, bkwd]; Finish[par]; RETURN}; refPairColls: PUBLIC Space ~ NEW [SpacePrivate _ [ Equal: RefPairCollsEqual, Hash: HashRefPairColl, Compare: CompareRefPairColls, other: List.PutAssoc[$Name, "ref PairColls", NIL] ]]; RefPairCollsEqual: PROC [data: REF ANY, elt1, elt2: Value] RETURNS [BOOL] ~ { pc1: REF PairColl ~ NARROW[elt1]; pc2: REF PairColl ~ NARROW[elt2]; RETURN [pc1^.Equal[pc2^]]}; HashRefPairColl: PROC [data: REF ANY, elt: Value] RETURNS [CARDINAL] ~ { pc: REF PairColl ~ NARROW[elt]; RETURN pc^.Hash[]}; CompareRefPairColls: PROC [data: REF ANY, elt1, elt2: Value] RETURNS [Basics.Comparison] ~ { pc1: REF PairColl ~ NARROW[elt1]; pc2: REF PairColl ~ NARROW[elt2]; RETURN [pc1^.Compare[pc2^]]}; Equal: PUBLIC PROC [a, b: PairColl, bounds: CollPair _ [passAll, passAll]] RETURNS [BOOL] ~ { minSide: Side ~ IF bounds[left]=passAll THEN right ELSE left; maxSide: Side ~ OtherSide[minSide]; minColl: Collection ~ bounds[minSide]; maxColl: Collection ~ bounds[maxSide]; mayDup: BOOL ~ a.MayDuplicate[]; spaces: SpacePair ~ a.Spaces[]; ByBound: PROC [side: Side] RETURNS [BOOL] ~ { otherSide: Side ~ OtherSide[side]; otherBound: Collection ~ bounds[otherSide]; applDir: Direction ~ From[side]; Test: PROC [val: Value] RETURNS [pass: BOOL] ~ { pass _ NOT a.Mapping[val, applDir].Intersection[otherBound].Equal[b.Mapping[val, applDir].Intersection[otherBound]]; RETURN}; RETURN [NOT bounds[side].Scan[Test].found]; }; IF mayDup # b.MayDuplicate THEN ERROR Cant[a]; IF spaces # b.Spaces[] THEN ERROR Cant[a]; IF spaces[left]=NIL OR spaces[right]=NIL THEN ERROR Cant[a]; IF mayDup THEN { Test: PROC [a, b: MaybePair] RETURNS [pass: BOOL _ FALSE] ~ { IF a.found#b.found THEN RETURN [TRUE]; IF NOT a.found THEN ERROR; pass _ NOT (spaces[left].SpaceEqual[a.pair[left], b.pair[left]] AND spaces[right].SpaceEqual[a.pair[right], b.pair[right]]); RETURN}; IF maxColl # passAll THEN ERROR; RETURN [NOT ParallelScanHalfRestriction[a, b, minColl, Test, minSide].found]; } ELSE IF a.Can[$Enumerate] AND b.Can[$Enumerate] THEN { Try: PROC [a, b: PairColl] RETURNS [BOOL] ~ { Test: PROC [pair: Pair] RETURNS [pass: BOOL] ~ { pass _ maxColl.HasMember[pair[maxSide]] AND NOT b.HasPair[pair]; RETURN}; RETURN [NOT a.ScanHalfRestriction[minColl, Test, minSide].found]; }; RETURN [Try[a, b] AND Try[b, a]]; } ELSE IF bounds[left].Can[$Enumerate] AND a.Can[$Image, LIST[$leftToRight]] AND b.Can[$Image, LIST[$leftToRight]] THEN RETURN ByBound[left] ELSE IF bounds[right].Can[$Enumerate] AND a.Can[$Image, LIST[$rightToLeft]] AND b.Can[$Image, LIST[$rightToLeft]] THEN RETURN ByBound[right] ELSE IF bounds[left].Can[$Enumerate] AND bounds[right].Can[$Enumerate] THEN { Mid: PROC [left: Value] RETURNS [pass: BOOL] ~ { Inner: PROC [right: Value] RETURNS [pass: BOOL] ~ { pass _ a.HasPair[[left, right]] # b.HasPair[[left, right]]; RETURN}; pass _ bounds[right].Scan[Inner].found; RETURN}; RETURN [NOT bounds[left].Scan[Mid].found]; } ELSE ERROR Cant[a]; }; Hash: PUBLIC PROC [pc: PairColl, bounds: CollPair _ [passAll, passAll]] RETURNS [hash: CARDINAL] ~ { minSide: Side ~ IF bounds[left]=passAll THEN right ELSE left; maxSide: Side ~ OtherSide[minSide]; minColl: Collection ~ bounds[minSide]; maxColl: Collection ~ bounds[maxSide]; spaces: SpacePair ~ pc.Spaces[]; PerPair: PROC [pair: Pair] RETURNS [pass: BOOL _ FALSE] ~ { IF NOT maxColl.HasMember[pair[maxSide]] THEN RETURN; hash _ hash + spaces[left].SpaceHash[pair[left]] + spaces[right].SpaceHash[pair[right]]; RETURN}; hash _ 0; IF spaces[left]=NIL OR spaces[right]=NIL OR spaces[left].Hash=CantHash OR spaces[right].Hash=CantHash THEN Cant[pc]; [] _ pc.ScanHalfRestriction[minColl, PerPair, minSide]; RETURN}; Compare: PUBLIC PROC [a, b: PairColl, bounds: CollPair _ [passAll, passAll]] RETURNS [c: Basics.Comparison] ~ { minSide: Side ~ IF bounds[left]=passAll THEN right ELSE left; maxSide: Side ~ OtherSide[minSide]; minColl: Collection ~ bounds[minSide]; maxColl: Collection ~ bounds[maxSide]; mayDup: BOOL ~ a.MayDuplicate[]; spaces: SpacePair ~ a.Spaces[]; orderStyle: OrderStyle ~ a.OrderStyleOf; IF mayDup # b.MayDuplicate THEN ERROR Cant[a]; IF spaces # b.Spaces[] THEN ERROR Cant[a]; IF spaces[left]=NIL OR spaces[right]=NIL OR spaces[left].Compare=CantCompare OR spaces[right].Compare=CantCompare THEN ERROR Cant[a]; IF orderStyle # b.OrderStyleOf[] THEN ERROR Cant[a]; IF mayDup OR orderStyle#none THEN { Test: PROC [a, b: MaybePair] RETURNS [pass: BOOL _ FALSE] ~ { IF a.found#b.found THEN { c _ IF a.found THEN greater ELSE less; RETURN [TRUE]}; IF NOT a.found THEN ERROR; c _ spaces[left].SpaceCompare[a.pair[left], b.pair[left]]; IF c=equal THEN c _ spaces[right].SpaceCompare[a.pair[right], b.pair[right]]; pass _ c#equal; RETURN}; IF maxColl#passAll THEN ERROR; c _ equal; [] _ ParallelScanHalfRestriction[a, b, minColl, Test, minSide]; RETURN}; ERROR Cant[a]; }; OrderBySide: PUBLIC PROC [side: Side, o: Colls.Ordering] RETURNS [Ordering] ~ { RETURN OrderByBoth[side, o, Colls.unordered]}; OrderByBoth: PUBLIC PROC [highSide: Side, high, low: Colls.Ordering] RETURNS [Ordering] ~ { po: PairedOrdering ~ NEW [PairedOrderingPrivate _ [highSide, high, low]]; care: CARDINAL ~ (IF high#Colls.unordered THEN highSide.ORD+1 ELSE 0) + (IF low#Colls.unordered THEN OtherSide[highSide].ORD+1 ELSE 0); RETURN [[PairedCompare, po, VAL[care]]]; }; PairedOrdering: TYPE ~ REF PairedOrderingPrivate; PairedOrderingPrivate: TYPE ~ RECORD [highSide: Side, high, low: Colls.Ordering]; PairedCompare: PROC [data: REF ANY, elt1, elt2: Pair] RETURNS [c: Basics.Comparison _ equal] --PairCompareProc-- ~ { po: PairedOrdering ~ NARROW[data]; lowSide: Side ~ OtherSide[po.highSide]; IF po.high#Colls.unordered THEN c _ po.high.Compare[po.high.data, elt1[po.highSide], elt2[po.highSide]]; IF c=equal AND po.low#Colls.unordered THEN c _ po.low.Compare[po.low.data, elt1[lowSide], elt2[lowSide]]; RETURN}; FnFromProc: PUBLIC PROC [Apply: PROC [data: REF ANY, v: Value] RETURNS [mv: MaybeValue], spaces: SpacePair _ [refs, refs], data: REF ANY _ NIL, constant, oneToOne: BOOL _ FALSE, ScanInverse: PROC [data: REF ANY, v: Value, Test: Tester] RETURNS [MaybePair] _ NIL] RETURNS [Function] ~ { pf: ProcFn ~ NEW [ProcFnPrivate _ [spaces, Apply, ScanInverse, data]]; RETURN [[procClass[constant][oneToOne], pf]]; }; procClass: ARRAY --constant--BOOL OF ARRAY --oneToOne--BOOL OF PairCollClass ~ [ FALSE: [ FALSE: CreateClass[[ Primitive: ProcPrimitive, Apply: ProcApply, ScanHalfRestriction: ProcScanHalfRestriction, Spaces: ProcSpaces, functional: [TRUE, FALSE], mayDuplicate: FALSE, mutability: readonly]], TRUE: CreateClass[[ Primitive: ProcPrimitive, Apply: ProcApply, ScanHalfRestriction: ProcScanHalfRestriction, Spaces: ProcSpaces, functional: [TRUE, TRUE], mayDuplicate: FALSE, mutability: readonly]]], TRUE: [ FALSE: CreateClass[[ Primitive: ProcPrimitive, Apply: ProcApply, ScanHalfRestriction: ProcScanHalfRestriction, Spaces: ProcSpaces, functional: [TRUE, FALSE], mayDuplicate: FALSE, mutability: constant]], TRUE: CreateClass[[ Primitive: ProcPrimitive, Apply: ProcApply, ScanHalfRestriction: ProcScanHalfRestriction, Spaces: ProcSpaces, functional: [TRUE, TRUE], mayDuplicate: FALSE, mutability: constant]]] ]; ProcFn: TYPE ~ REF ProcFnPrivate; ProcFnPrivate: TYPE ~ RECORD [ spaces: SpacePair, Apply: PROC [data: REF ANY, v: Value] RETURNS [mv: MaybeValue], ScanInverse: PROC [data: REF ANY, v: Value, Test: Tester] RETURNS [MaybePair], data: REF ANY ]; ProcPrimitive: PROC [pc: PairColl, op: ATOM, args: ArgList _ NIL] RETURNS [PrimitiveAnswer] ~ { pf: ProcFn ~ NARROW[pc.data]; SELECT op FROM $Apply => RETURN [IF GetDir[args, 1]=leftToRight THEN yes ELSE no]; $ScanHalfRestriction => RETURN [IF GetSide[args, 1]=right AND pf.ScanInverse#NIL AND NOT GetBool[args, 2] THEN yes ELSE no]; ENDCASE => RETURN [pass]; }; ProcApply: PROC [pc: PairColl, v: Value, dir: Direction] RETURNS [MaybeValue] ~ { pf: ProcFn ~ NARROW[pc.data]; SELECT dir FROM leftToRight => RETURN pf.Apply[pf.data, v]; rightToLeft => RETURN DefaultApply[pc, v, dir]; ENDCASE => ERROR; }; ProcScanHalfRestriction: PROC [pc: PairColl, side: Side, coll: Collection, Test: Tester, bkwd: BOOL] RETURNS [mp: MaybePair] ~ { pf: ProcFn ~ NARROW[pc.data]; IF side=right AND pf.ScanInverse#NIL AND NOT bkwd THEN { PerRight: PROC [val: Value] RETURNS [pass: BOOL] ~ { pass _ (mp _ pf.ScanInverse[pf.data, val, Test]).found; RETURN}; [] _ coll.Scan[PerRight]; RETURN}; RETURN DefaultScanHalfRestriction[pc, side, coll, Test, bkwd]; }; ProcSpaces: PROC [pc: PairColl] RETURNS [SpacePair] ~ { pf: ProcFn ~ NARROW[pc.data]; RETURN [pf.spaces]; }; GetSide: PUBLIC PROC [args: ArgList, i: NAT, default: Side _ left] RETURNS [Side] ~ { IF i<1 THEN ERROR; WHILE i>1 AND args#NIL DO args _ args.rest; i _ i - 1 ENDLOOP; RETURN [IF args=NIL THEN default ELSE SELECT args.first FROM $left => left, $right => right, ENDCASE => ERROR]}; FromSide: PUBLIC PROC [x: Side] RETURNS [ATOM] ~ {RETURN [IF x=left THEN $left ELSE $right]}; ReverseOrdering: PUBLIC PROC [o: Ordering] RETURNS [ro: Ordering] ~ { RETURN [[CompareReversal, NEW [Ordering _ o], o.sideCare]]; }; CompareReversal: PROC [data: REF ANY, elt1, elt2: Pair] RETURNS [Basics.Comparison] ~ { o: REF Ordering ~ NARROW[data]; RETURN o.Compare[o.data, elt2, elt1]}; BeRope: PROC [r: ROPE] RETURNS [ROPE] ~ INLINE {RETURN[r]}; Start: PROC ~ { Atom.PutProp[prop: kindKey, val: $composite, atom: $Mapping]; Atom.PutProp[prop: kindKey, val: $composite, atom: $Enumerate]; Atom.PutProp[prop: kindKey, val: $composite, atom: $EnumerateImage]; Atom.PutProp[prop: kindKey, val: $composite, atom: $EnumerateMapping]; Atom.PutProp[prop: kindKey, val: $composite, atom: $EnumerateHalfRestriction]; Atom.PutProp[prop: kindKey, val: $composite, atom: $ScanImage]; Atom.PutProp[prop: kindKey, val: $composite, atom: $ScanMapping]; Atom.PutProp[prop: kindKey, val: $composite, atom: $First]; Atom.PutProp[prop: kindKey, val: $composite, atom: $Last]; Atom.PutProp[prop: kindKey, val: $composite, atom: $Pop]; Atom.PutProp[prop: kindKey, val: $composite, atom: $Next]; Atom.PutProp[prop: kindKey, val: $composite, atom: $Prev]; Atom.PutProp[prop: kindKey, val: $composite, atom: $Empty]; Atom.PutProp[prop: kindKey, val: $composite, atom: $MappingSize]; Atom.PutProp[prop: kindKey, val: $composite, atom: $AddPair]; Atom.PutProp[prop: kindKey, val: $composite, atom: $Store]; Atom.PutProp[prop: kindKey, val: $composite, atom: $Replace]; Atom.PutProp[prop: kindKey, val: $composite, atom: $Insert]; Atom.PutProp[prop: kindKey, val: $composite, atom: $Inserted]; Atom.PutProp[prop: kindKey, val: $composite, atom: $RemPair]; Atom.PutProp[prop: kindKey, val: $composite, atom: $Delete]; Atom.PutProp[prop: kindKey, val: $composite, atom: $IsIntFn]; Atom.PutProp[prop: kindKey, val: $composite, atom: $AsIntFn]; Atom.PutProp[prop: kindKey, val: $class , atom: $Widen]; Atom.PutProp[prop: kindKey, val: $class , atom: $HasPair]; Atom.PutProp[prop: kindKey, val: $classD , atom: $Image]; Atom.PutProp[prop: kindKey, val: $classD , atom: $Apply]; Atom.PutProp[prop: kindKey, val: $classB , atom: $Scan]; Atom.PutProp[prop: kindKey, val: $classSB, atom: $ScanHalfRestriction]; Atom.PutProp[prop: kindKey, val: $classBR, atom: $Extremum]; Atom.PutProp[prop: kindKey, val: $class , atom: $Get3]; Atom.PutProp[prop: kindKey, val: $class , atom: $Size]; Atom.PutProp[prop: kindKey, val: $classD , atom: $ImageSize]; Atom.PutProp[prop: kindKey, val: $class , atom: $Copy]; Atom.PutProp[prop: kindKey, val: $class , atom: $Insulate]; Atom.PutProp[prop: kindKey, val: $class , atom: $ValueOf]; Atom.PutProp[prop: kindKey, val: $class , atom: $Freeze]; Atom.PutProp[prop: kindKey, val: $class , atom: $Thaw]; Atom.PutProp[prop: kindKey, val: $classS , atom: $CollectionOn]; Atom.PutProp[prop: kindKey, val: $classS , atom: $CurSetOn]; Atom.PutProp[prop: kindKey, val: $class , atom: $AddColl]; Atom.PutProp[prop: kindKey, val: $class , atom: $RemColl]; Atom.PutProp[prop: kindKey, val: $classS , atom: $DeleteColl]; Atom.PutProp[prop: kindKey, val: $class , atom: $QuaIntFn]; Atom.PutProp[prop: kindKey, val: $class , atom: $Spaces]; Atom.PutProp[prop: kindKey, val: $class , atom: $OrderingOf]; }; Start[]; END. bPairCollectionsImpl.Mesa Last tweaked by Mike Spreitzer on October 16, 1987 10:23:28 am PDT Ê.¥˜code™KšœB™B—K˜KšÏk œ;˜DK˜šÏnœœ˜"Kšœœ˜Kšœ2˜9Kšœ˜K˜—K˜Kšœœžœ+˜;K˜Kšžœœœœ˜)K˜š žœœœœœœ˜NKšœ˜—K˜Kšœœœ>˜QK˜Kšœœ3˜AKšœ œœ ˜0K˜Kšžœœœ˜Kšœœ!˜3Kšœ œ ˜1Kšœ œ˜/Kšœ œ˜)K˜šž œ˜šœ˜Kšœ œœœ˜Kšœœœ˜"—Kšœ˜"K•StartOfExpansion%[key: REF ANY, aList: List.AList]šœœ1˜Nš žœœœœœœ˜1Kšœœœ œ˜GKšœ˜—Kšœœ˜ Kšœœœ˜3Kšœœœ˜;Kšœœœ˜3Kšœœœ˜3Kšœœœ˜/Kšœ.œœ2˜kKšœœœ˜?Kšœœœ˜/Kšœœœ˜/Kšœœœ˜CKšœœœ˜/Kšœœœ˜?Kšœœœ˜;Kšœœœ˜7Kšœœœ˜/Kšœ œœ$˜OKšœœœ˜?Kšœœœ˜;Kšœœœ˜;Kšœœœ ˜GKšœœœ˜?Kšœœœ ˜GK˜Kšœ8˜8Kšœ&œœ˜EKšœ%œ!˜IKšœœ˜(K˜—K˜š ž œœœœœœ˜PK–[atom: ATOM, prop: REF ANY]šœœœ)˜6šœ˜Kšœ9œ˜>Kšœœ˜—š œœœœ"˜MKšœœœ˜Kšœœœ˜Kšœœ˜ Kšœœ˜—Kšœœ7˜UKšœœœ˜&Kšœ œœœ*˜CKšœ œ œ)˜Gšœœ˜Kšœ œ˜šœœ˜Kšœ œ˜Kšœ$˜$Kšœ&˜&Kšœ(œœ˜\Kšœ,œ˜KKšœ+˜+Kšœœ˜—Kšœœ˜—K˜—K˜š ž œœœœœœ˜^–[atom: ATOM, prop: REF ANY]šœ'˜1Kšœ9œ˜>šœœ˜Kšœ œ˜/Kšœœ˜0Kšœœ!˜:Kšœœ!˜Kšœœœ%˜QKšœ œ)˜8Kšœ œ)˜8šœ œœ˜8K˜Kšœ(˜(K˜ Kšœœ˜—Kšœœ!˜7Kšœ œ˜1Kšœ œ˜/Kšœ œ˜1Kšœ œ˜0Kšœ œ˜2Kšœ œ˜1Kšœ œ"˜3Kšœ œ ˜2Kšœ œ ˜2Kšœœ˜—Kšœœ˜—Kšœœœ ˜3šœœ˜Kšœ˜šœ ˜ Kšœœœœœœœ ˜¬Kš œœœœœœ ˜IKšœ˜ —Kšœ7˜7Kšœ;˜;Kš œ œœ œœ œ˜bšœ˜Kšœœ1˜PKšœœ-˜K—Kš œœ*œ œœœœ˜£Kš œ œœœ-œœ ˜–Kšœ1˜1KšœA˜AKšœ˜Kšœ˜Kšœ œœ œG˜ˆKš œœœœœ˜CKšœ>˜>Kšœ œœ7œ˜nKšœ&œœœ ˜]Kšœ˜Kšœ˜Kšœœœ œ+˜lKšœœ˜—K˜—K˜š žœœœœœ˜NK˜K˜ š žœœœœœÏc œ˜BKšœ7œ4˜nK˜—Kš œœœœIœ1˜ÏKš œœœœœJœ/˜ÓKš œœœœœœ˜LKšœ ˜Kšœ˜—K˜šž œœœ2œ ˜_Kšœœ&˜9KšœHœœ ˜tK˜—K˜Kšœ œœ˜'Kšœœœ2˜QK˜šžœœžœœœœœ˜NKšœœ˜š žœœœœœ˜8Kšœœ˜%—š ž œœœœœ˜?Kšœ)œ˜LKšœ˜—Kšœ(œœ?œ˜¯Kšœ˜—K˜šž œœœ*œ˜iKšœœœ4˜TKšœ"˜"šœ ˜Kšœœ˜ Kšœœœ˜#Kšœœ˜—K˜—K˜šž œœœžœœœœ˜YKš žœœ œœœ˜AKšœ˜Kšœ˜—K˜š ž œœœžœœœ"˜kKšœœ'œ˜LKšœœ'œ˜Mšœœœ˜Kšœ œœœœœœœœœœœœœ˜uKšœ4˜4K˜—š œœœ œ œ˜=Kšœœœ˜Kšžœœœ ˜/Kšœœ˜Kšœœœœœœœœœ˜lKšœ˜—Kšœ ˜Kšœ˜—K˜šžœœœ"žœœ1œœ˜ŒKš žœœ œœœ˜LKšœ;˜;Kšœ˜—K˜šžœœœ"žœœ(œœ˜Kš žœœœœœ˜GKšœ4˜4Kšœ˜—K˜šž œœœ"žœ4œœœ"˜§Kš žœœœœœ#˜UKšœ:˜:Kšœ˜—K˜š žœœœ.žœœœ˜†šž œœœ"˜9šžœœ œœ˜0Kšœ.˜.Kšœ œ˜šžœœ œœ˜2K˜Kšœœœ˜.Kšœ˜—K˜(Kšœ˜—K˜Kšœ˜—šžœœœ˜(š žœœœœœ˜;Kšœ"œ ˜1Kšœ˜—K˜Kšœ˜—Kšœ œœ˜6Kšœ œœ˜:Kšœ œ&˜6Kšœœ(˜:Kšœ œ'˜8Kšœœ-˜?Kš œœ œœœ ˜7Kšœœ œœ ˜)Kšœœ œœ ˜(Kšœ œœœœœœ œœœ œ ˜‘Kšœœ œ œ ˜5K˜—K˜š žœœœœœ˜ZKš žœœ œœœ œ˜DKš žœœ œœœ œ˜HKšœœ!œ˜XKšœœ˜"šœ œœ˜Kšœ#œœœ˜Ašœœ ˜"Kš œœœ œœ˜4Kšœ˜—K˜—Kšœ˜—K˜šž œœœœ"˜]Kšœ&œ ˜4Kšœ&œ ˜3Kšœœ ˜Kšœœœ˜Kšœ ˜ š žœœ œœœ˜7Kšœ0œ3œœ˜‡Kšœœœ˜Kšœ œ˜K˜—Kš œœœœœ ˜7Kšœ˜Kšœ˜Kšœœœ˜'Kšœ˜—K˜š ž œœœœœœ˜MKšžœœœœ&˜KK˜ K˜Kšœ˜—K˜š žœœœ9œœœ˜tKšžœœ œœ&˜LK˜ K˜#Kšœ˜—K˜Kšž œœœœ˜KK˜Kšžœœœœœœœœœ˜œK˜Kš ž œœœœœœ ˜Kš ž œœœœœ ˜nK˜šžœœœœ ˜PKšœœ(˜Cšœœ˜-K˜K˜Kšœœ˜—KšœCœœœ4˜¤K˜—K˜Kšœœœ˜5Kšœœœ˜BK˜šžœœžœœœœœ˜QKšœœ˜%Kšžœœ*˜4K˜Kšœ˜—K˜šžœœœœ˜NKšœœœœ ˜TK˜—K˜šžœœœ-œœœœ˜€KšœL˜LKšœœ ˜šœœ ˜"š œœ œœ˜9K˜Kšœ˜Kšœ"˜"Kšœœ˜—Kšœ˜—Kšœ˜—K˜šž œœœ2˜IKšœR˜Ršœœ ˜"Kš œœœœœ˜QKšœ˜—Kšœ˜—K˜šž œœœ-˜DKšœ8˜8šœœ ˜"Kš œœœœœ˜QKšœ˜—Kšœ˜—K˜Kšžœœœ5œœœœ ˜¹Kšžœœœ+œ œœœ ˜·KšžœœœBœœœœœ ˜ÍK˜Kšž œœœœœœœ˜Ušžœœœœ˜DKšœœœ ˜5K˜!Kšœœœœœ"œ#œ ˜€Kšœœ˜9K˜—K˜š žœœœœœ˜;Kšœœ˜%—K˜š ž œœœœœ˜UKšœœ œ˜%KšœI˜IKšœ œ:˜IKšœ˜ —K˜šžœœœ$žœ+œœœœ˜¯Kšœœ#˜6Kšœœœ˜1Kšœœœ˜1šž œœœœœ œœ˜PKšœœœ˜š˜Kš œœœœ œ˜1Kš œœœœ œ˜1Kšœœ˜0Kšœ˜—Kšœ˜—š žœœœœœ˜4Kšœœœ˜Kšœœ˜$Kš œ ˜Kšœ˜—Kšœœ˜'š˜Kšœœœœ˜!Kšœ-œœ˜ZK˜ Kšœ œœ˜Kšœ˜—Kšœ˜Kšœ˜Kšœ˜—K˜Kšœœ ˜Kšœ œœ˜%šœœ œœ˜*Kšœœœ ˜Kš œœœœœœ˜(Kšœœœ˜Kšœ œ)˜:Kš œœœ œœ ˜4K˜—K˜šžœœCœ˜Uš žœœœœœ˜;šžœœœ˜(Kšœœœ˜K˜Kšœœ˜Kš œ ˜Kš œœœœ œ˜6K˜Kšœ˜—Jšœ˜Jšœ˜—šžœœœ˜&Kšœœœ˜Kšœœ˜Kšœœ˜Kš œ ˜Kšœ˜—šœ ˜Kšœ'˜+KšœC˜G—K˜ Kšœ˜—K˜šœœ œ˜2Kšžœ˜Kšžœ˜Kšžœ˜Kšœ-œ˜1K˜—K˜š žœœœœœœ˜MKšœœ œ˜!Kšœœ œ˜!Kšœ˜—K˜š žœœœœœœ˜HKšœœ œ˜Kšœ ˜—K˜š žœœœœœ˜\Kšœœ œ˜!Kšœœ œ˜!Kšœ˜—K˜š žœœœ9œœ˜]Kšœœœœ˜=Kšœ#˜#Kšœ&˜&Kšœ&˜&Kšœœ˜ K˜šžœœœœ˜-K˜"K˜+Kšœ ˜ šžœœœœ˜0Kšœœj˜tKšœ˜—Kšœœ ˜+K˜—Kšœœœ ˜.Kšœœœ ˜*Kš œœœœœœ ˜<šœœ˜š žœœœœœ˜=Kšœœœœ˜&Kšœœ œœ˜Kšœœ6œ9˜|Kšœ˜—Kšœœœ˜ KšœœB˜MK˜—šœœœœ˜6šžœœœœ˜-šžœœœœ˜0Kšœ(œœ˜@Kšœ˜—Kšœœ6˜AK˜—Kšœ œ ˜!K˜—Kšœœœœœœœœ˜ŠKšœœœœœœœœ˜Œšœœœœ˜Mšžœœœœ˜0šžœœœœ˜3K˜;Kšœ˜—K˜'Kšœ˜—Kšœœ˜*K˜—Kšœœ ˜K˜—K˜š žœœœ7œœ˜dKšœœœœ˜=Kšœ#˜#Kšœ&˜&Kšœ&˜&K˜ š žœœœœœ˜;Kšœœ"œœ˜4K˜XKšœ˜—K˜ Kšœœœœœœœ ˜tK˜7Kšœ˜—K˜šžœœœ9œ˜oKšœœœœ˜=Kšœ#˜#Kšœ&˜&Kšœ&˜&Kšœœ˜ K˜K˜(Kšœœœ ˜.Kšœœœ ˜*Kšœœœœœ"œ#œœ ˜…Kšœœœ ˜4šœœœ˜#š žœœœœœ˜=šœœ˜Kšœœ œ œ˜&Kšœœ˜—Kšœœ œœ˜Kšœ:˜:Kšœ œ>˜MK˜Kšœ˜—Kšœœœ˜K˜ Kšœ?˜?Kšœ˜—Kšœ ˜K˜—K˜šž œœœ!œ˜OKšœ(˜.—K˜šž œœœ-œ˜[Kšœœ1˜Išœœ˜Kš œœœ œœ˜6Kš œœœœœ˜?—Kšœœ ˜(K˜—K˜Kšœœœ˜1Kšœœœ-˜QK˜š ž œœœœœ Ÿœ˜tKšœœ˜"K˜'KšœœI˜hKšœ œœ?˜iKšœ˜—K˜š*ž œœœžœœœœ œ;œœœœœž œœœœ žœ œœœ˜Kšœ œ6˜FKšœ'˜-K˜—K˜šœ œŸ œœœŸ œœ˜Pšœ˜šœ˜Kšž œ˜Kšžœ ˜Kšžœ˜-Kšžœ ˜Kšœ œœ˜Kšœœ˜K˜—šœ˜Kšž œ˜Kšžœ ˜Kšžœ˜-Kšžœ ˜Kšœ œœ˜Kšœœ˜K˜——šœ˜šœ˜Kšž œ˜Kšžœ ˜Kšžœ˜-Kšžœ ˜Kšœ œœ˜Kšœœ˜K˜—šœ˜Kšž œ˜Kšžœ ˜Kšžœ˜-Kšžœ ˜Kšœ œœ˜Kšœœ˜K˜——K˜—K˜Kšœœœ˜!šœœœ˜K˜Kš žœœœœ œ˜?Kš ž œœœœ žœ œ ˜NKšœœ˜ Kšœ˜—K˜š ž œœœœœ˜_Kšœ œ ˜šœ˜Kš œ œœœœ˜CKšœœœœœœœœœ˜|Kšœœ˜—K˜—K˜šž œœ*œ˜QKšœ œ ˜šœ˜Kšœœ˜+Kšœœ˜/Kšœœ˜—K˜—K˜š žœœ.žœœœ˜€Kšœ œ ˜š œ œœœœœ˜8šžœœœœ˜4Kšœ7˜7Kšœ˜—K˜Kšœ˜—Kšœ8˜>K˜—K˜šž œœœ˜7Kšœ œ ˜Kšœ˜K˜—K˜š žœœœœœ ˜UKšœœœ˜Kš œœœœœ˜>š œœœœ œœ ˜˜>K–/[atom: ATOM, prop: REF ANY, val: REF ANY]šœ=˜=K–/[atom: ATOM, prop: REF ANY, val: REF ANY]šœ<˜˜>K–/[atom: ATOM, prop: REF ANY, val: REF ANY]šœ<˜˜>K˜—K˜K˜K˜Kšœ˜—…—~ü®