DIRECTORY Atom USING [GetPropFromList], Buttons, Containers, DB, DBIcons USING [GetIcon], DBNames USING[MakeName, NameToEntity], DefaultNutUtilities, --EntityEditor, Icons USING [IconFlavor, NewIconFromFile], InputFocus USING [SetInputFocus], IO, Menus USING [AppendMenuEntry, CreateMenu, Menu, MenuProc, SetGuarded, FindEntry], NoteEditor, Nut, NutButtons, NutOps, NutViewer, Rope, SafeStorage USING [NarrowRefFault], TiogaOps USING [InsertRope], TuplesEditor, ViewerLocks, ViewerOps, ViewerClasses, ViewerTools; NutDefaultImpl: CEDAR PROGRAM IMPORTS Atom, DB, DBIcons, DBNames, DefaultNutUtilities, InputFocus, IO, Nut, NutOps, NutViewer, Icons, Menus, NoteEditor, Rope, SafeStorage, TiogaOps, TuplesEditor, ViewerOps, ViewerTools SHARES ViewerLocks = BEGIN OPEN DB, NutViewer, ViewerClasses; Viewer: TYPE = ViewerClasses.Viewer; editorMenu: Menus.Menu _ Menus.CreateMenu[]; ConvertViewerToEntity: PROC[v: Viewer, create: BOOL _ FALSE] RETURNS[e: Entity, name: ROPE] = BEGIN eName, domain: ROPE; segment: DB.Segment; [segment, domain, eName] _ Nut.GetNutInfo[v]; IF segment = NIL THEN RETURN; name _ DBNames.MakeName[segment, domain, eName]; e _ DBNames.NameToEntity[name, create] END; FreezeProc: Menus.MenuProc = { [] _ Nut.SetFrozenProperty[NARROW[parent], TRUE] }; ResetProc: Menus.MenuProc = BEGIN viewer: Viewer = NARROW[parent]; seg: Segment; domain: ROPE; eName: ROPE; [seg, domain, eName] _ Nut.GetNutInfo[viewer]; InputFocus.SetInputFocus[]; -- kill the caret viewer.child _ NIL; TuplesEditor.ResetTuples[viewer]; ViewerOps.PaintViewer[viewer, $all]; [] _ DefaultEdit[eName: eName, domain: domain, segment: seg, lastSpawned: viewer]; Menus.SetGuarded[ Menus.FindEntry[viewer.menu, "Reset"], FALSE ]; END; SaveProc: Menus.MenuProc = BEGIN viewer: Viewer = NARROW[parent]; newV: Viewer; seg: Segment; d: Domain; dName: ROPE; eName: ROPE; e: Entity; [seg, dName, eName]_ Nut.GetNutInfo[viewer]; d _ DB.DeclareDomain[dName, seg]; e _ DB.DeclareEntity[d, eName, NewOrOld ]; TRUSTED BEGIN --entityRow: VTable = GetTableEntry[ table: table, row: 2 ]; notes: Viewer = NARROW[ ViewerOps.FetchProp[viewer, $Notes]]; errors: BOOL_ TuplesEditor.SaveTuples[viewer: notes, newEntity: e].errors; --EntityEditor.SaveEntities[viewer: entityRow, newOf: e]; NoteEditor.SaveNote[newEntity: e, viewer: notes, update: TRUE]; IF errors THEN NutViewer.Message[viewer, "You may correct any errors and save again."] ELSE BEGIN newV _ NutViewer.ReplaceViewer[eName: eName, domain: dName, seg: seg, parent: viewer]; [] _ DefaultDisplay[eName: eName, domain: dName, segment: seg, lastSpawned: newV]; END; END; END; MergeProc: Menus.MenuProc = BEGIN viewer: Viewer = NARROW[parent]; seg: Segment; d: Domain; dName: ROPE; eName: ROPE; e: Entity; otherEntity: Entity; otherName: ROPE = ViewerTools.GetSelectionContents[]; [seg, dName, eName] _ Nut.GetNutInfo[viewer]; d _ DB.DeclareDomain[dName, seg]; otherEntity _ IF otherName=NIL THEN NIL ELSE DB.FetchEntity[d, otherName, seg]; e_ DB.FetchEntity[d, eName, seg ! DB.Error => { e _ NIL; CONTINUE } ]; IF e = NIL THEN Message[viewer, "This entity does not exist yet!"] ELSE IF otherName=NIL THEN Message[viewer, "Please select name for entity to merge with!"] ELSE IF otherEntity=NIL THEN Message[viewer, "Selected entity not found in this domain!"] ELSE TRUSTED BEGIN displayViewer: Viewer = viewer.child; newV: Viewer; NutViewer.Message[ viewer, "Copying ", eName, " to ", Rope.Concat[otherName, ", and deleting it..."]]; []_ TuplesEditor.MergeTuples[viewer: displayViewer, newEntity: otherEntity]; --EntityEditor.SaveEntities[viewer: entityRow, newOf: otherEntity]; NoteEditor.SaveNote[newEntity: otherEntity, update: TRUE, viewer: NARROW[ViewerOps.FetchProp[viewer, $Notes], Viewer] ]; DB.DestroyEntity[e]; -- Get rid of old entity, its relationships have been moved newV _ NutViewer.ReplaceViewer[eName: eName, domain: dName, seg: seg, parent: viewer]; [] _ DefaultDisplay[eName: eName, domain: dName, segment: seg, lastSpawned: newV]; END; END; RenameProc: Menus.MenuProc = { ENABLE DB.Error => IF code=NonUniqueEntityName THEN {NutViewer.Message[NARROW[parent], "Entity already exists with that name!"]; CONTINUE}; viewer: Viewer = NARROW[parent]; seg: Segment; d: Domain; dName: ROPE; eName: ROPE; e: Entity; newName: ROPE = ViewerTools.GetSelectionContents[]; [seg, dName, eName]_ Nut.GetNutInfo[viewer]; d _ DB.DeclareDomain[dName, seg]; e_ DB.FetchEntity[d, eName, seg ]; IF e = NIL THEN Message[viewer, "Entity does not exist yet!"] ELSE IF newName=NIL THEN Message[viewer, "Please select new name for entity first!"] ELSE { DB.ChangeName[e, newName]; ViewerOps.AddProp[viewer, $EntityName, newName]; ViewerOps.AddProp[viewer, $Entity, e]; viewer.name_ Rope.Cat[NutOps.SafeNameOf[d],": ", newName]; ViewerOps.PaintViewer[viewer, caption] }; }; EraseAllProc: Menus.MenuProc = { viewer: Viewer = NARROW[parent]; seg: Segment; d: Domain; dName: ROPE; eName: ROPE; e: Entity; [seg, dName, eName]_ Nut.GetNutInfo[viewer]; d _ DB. DeclareDomain[dName, seg]; e_ DB.FetchEntity[d, eName, seg ! DB.Error => { e _ NIL; CONTINUE } ]; IF e = NIL THEN RETURN; DB.DestroyEntity[e]; ViewerOps.DestroyViewer[viewer]; }; AddProc: Menus.MenuProc = TRUSTED { viewer: Viewer = NARROW[parent]; entityRow: Viewer = viewer.child; selected: Viewer = ViewerTools.GetSelectedViewer[]; entity: Entity; IF selected=NIL THEN {NutViewer.Error[viewer, "No viewer selected!"]; RETURN}; entity_ ConvertViewerToEntity[ParentOf[selected]].e; --EntityEditor.NewEntry[ entity, entityRow ]; }; ParentOf: PROC[ v: Viewer ] RETURNS[ parent: Viewer ] = { parent _ v; WHILE parent.parent # NIL DO parent _ parent.parent ENDLOOP }; DefaultEdit: PUBLIC Nut.NutProc = TRUSTED BEGIN d: Domain = DB.DeclareDomain[domain, segment]; al: LIST OF Attribute = NutOps.GetRefAttributes[d]; e: DB.Entity; newV: ViewerClasses.Viewer = NutViewer.CreateDefaultViewer[replace: lastSpawned, domain: domain, eName: eName, segment: segment]; e _ DeclareEntity[d, eName, OldOnly]; ViewerOps.SetMenu[newV, editorMenu]; newV.child _ NIL; ViewerOps.PaintViewer[newV, all]; [] _ TuplesEditor.DisplayTuples[e, al, newV]; [] _ NoteEditor.DisplayNote[entity: e, sibling: newV.child, segment: segment]; RETURN[newV] END; displayerMenu: Menus.Menu _ Menus.CreateMenu[]; DefaultDisplay: PUBLIC Nut.NutProc = TRUSTED BEGIN lastViewer: Viewer; d: DB.Domain = DB.DeclareDomain[domain, segment]; e: DB.Entity _ DB.FetchEntity[d, eName, segment]; newV: ViewerClasses.Viewer = NutViewer.CreateDefaultViewer[replace: lastSpawned, domain: domain, eName: eName, segment: segment]; ViewerOps.SetMenu[newV, displayerMenu]; lastViewer_ BuildTupleWindowButtons[e, segment, newV]; [] _ NoteEditor.DisplayNote[entity: e, sibling: lastViewer, segment: segment, noEdits: TRUE]; ViewerOps.PaintViewer[newV, all]; RETURN[newV] END; BuildTupleWindowButtons: PROC[e: Entity, seg: Segment, v: Viewer] RETURNS [Viewer] = BEGIN alT: AttributeList; t: Relship; myRel: Relation; tuples: RelshipSet; lastButton: Viewer; myAttrs: AttributeList; myAttrs_ RemoveSpecialAttributesFrom[DB.GetAllRefAttributes[e], seg]; lastButton_ NutViewer.Initialize[v]; FOR alT_ myAttrs, alT.rest UNTIL alT=NIL DO skipRelationName: BOOL _ FALSE; lastRelButton: Viewer _ NIL; IF Null[alT.first] THEN LOOP; myRel_ V2E[GetP[alT.first, aRelationIs]]; tuples_ RelationSubset[myRel, LIST[[alT.first, e]]]; IF NutOps.RSetSize[RelationSubset[myRel, LIST[[alT.first, e]]]]#9999 THEN UNTIL Null[t_ NextRelship[tuples]] DO [lastRelButton, lastButton] _BuildTuplesButtons[ v, alT.first, myRel, t, lastButton, skipRelationName, lastRelButton]; IF skipRelationName = FALSE THEN skipRelationName _ TRUE; ENDLOOP ELSE BuildMultiTupleButtons[v, alT.first, myRel, tuples]; ReleaseRelshipSet[tuples]; ENDLOOP; RETURN[lastButton] END; BuildMultiTupleButtons: PROC[viewer: Viewer, a: Attribute, r: Relation, ts: RelshipSet] = {Message[viewer, "Too many ", GetName[r], "s to display"]}; BuildTuplesButtons: PROC[ v: Viewer, a: Attribute, r: Relation, t: Relship, lastButton: Viewer, skipRelButton: BOOL _ FALSE, lastRelButton: Viewer _ NIL] RETURNS[Viewer, Viewer] = BEGIN aValue: ROPE; al: AttributeList_ NutOps.RemoveAttribute[a, DB.VL2EL[DB.GetPList[r, aRelationOf]]]; relationButton: Viewer; IF skipRelButton THEN lastButton _ ButtonCopy[lastRelButton] ELSE lastButton_ MakeButton[ q: DBQueue[], name: GetName[r], proc: ProcessSelection, data: r, sib: lastButton, newLine: TRUE]; relationButton _ lastButton; FOR alT: AttributeList_ al, alT.rest UNTIL alT=NIL DO aValue_ GetFS[t, alT.first]; IF aValue.Length[]>0 THEN -- only print if non-null value lastButton_ MakeButton[ q: DBQueue[], name: Rope.Cat[GetName[alT.first], ": ", aValue], proc: ProcessSelection, sib: lastButton, data: GetF[t, alT.first], font: NEW[NutButtons.ButtonFontInfoRec _ [TRUE,,,]] ]; ENDLOOP; RETURN[relationButton, lastButton]; END; ButtonCopy: PROC[lastRelButton: Viewer] RETURNS[Viewer] = BEGIN newV: Viewer _ NEW[ViewerRec]; newV.wy _ lastRelButton.wy + lastRelButton.wh; newV.wx _ lastRelButton.wx; newV.ww _ lastRelButton.ww; newV.wh _ lastRelButton.wh; newV.parent _ lastRelButton.parent; RETURN[newV]; END; RemoveSpecialAttributesFrom: PROC [ old: LIST OF Attribute, seg: Segment] RETURNS[new: LIST OF Attribute] = { ENABLE DB.Error => {IF code=NotFound THEN {new_ old; CONTINUE}}; star: Relation = DeclareRelation["*", seg, OldOnly]; starOf: Attribute = DeclareAttribute[r: star, name: "of", version: OldOnly]; starIs: Attribute = DeclareAttribute[r: star, name: "is", version: OldOnly]; note: Relation = DeclareRelation["note", seg, OldOnly]; noteOf: Attribute = DeclareAttribute[r: note, name: "of", version: OldOnly]; new_ old; IF star # NIL THEN {new_ NutOps.RemoveAttribute[starOf, new]; new_ NutOps.RemoveAttribute[starIs, new]}; IF note # NIL THEN new _ NutOps.RemoveAttribute[noteOf, new]; RETURN[new] }; EditProc: Menus.MenuProc = BEGIN viewer: Viewer = NARROW[parent]; seg: DB.Segment; dName: ROPE; eName: ROPE; [seg, dName, eName]_ Nut.GetNutInfo[viewer]; [] _ DefaultEdit[ eName: eName, domain: dName, segment: seg, lastSpawned: viewer]; END; PasteNameProc: Menus.MenuProc = { viewer: Viewer = NARROW[parent]; eName: ROPE_ Nut.GetNutInfo[viewer].entity; TiogaOps.InsertRope[eName]; }; queryerMenu: Menus.Menu _ Menus.CreateMenu[]; queryerIcon: Icons.IconFlavor_ Icons.NewIconFromFile["Nut.Icons", 11]; qNumber: INT_ 0; entryHeight: INTEGER = 14; NextQNumber: PROC RETURNS[INT] = { RETURN[qNumber_ qNumber + 1] }; DefaultQuery: PUBLIC Nut.NutProc = BEGIN al: AttributeList; d: DB.Domain = DB.DeclareDomain[domain, segment]; newV: ViewerClasses.Viewer; IF DB.IsSystemEntity[d] THEN {Message[newV, "Query not allowed on system domains!"]; RETURN[NIL]}; newV _ NutViewer.CreateDefaultViewer[replace: lastSpawned, domain: domain, eName: eName, segment: segment]; ViewerOps.SetMenu[newV, queryerMenu]; newV.icon_ queryerIcon; al_ DB.GetDomainRefAttributes[d]; [] _ TuplesEditor.DisplayTuples[NIL, al, newV]; RETURN[newV] END; QueryProc: Menus.MenuProc = BEGIN viewer: Viewer = NARROW[parent]; seg: Segment_ NARROW[ViewerOps.FetchProp[viewer, $Segment] ]; dName: ROPE = V2S[ ViewerOps.FetchProp[viewer, $DomainName] ]; d: Domain = DeclareDomain[dName, seg]; number: INT = NextQNumber[]; answer: LIST OF Entity_ TuplesEditor.QueryTuples[viewer: viewer]; IF answer=NIL THEN Message[viewer, "No entities satisfied query!"] ELSE IF answer.rest=NIL THEN BEGIN Message[viewer, "One entity satisfied query; displaying it..."]; [] _ Nut.Display[eName: DB.NameOf[answer.first], domain: dName, segment: seg, parent: viewer]; END ELSE BEGIN Message[ viewer, "Entities satisfying query displayed in Answer viewer..."]; MultiDisplay[ entities: answer, title: IO.PutFR["Answer to %g query #%g", IO.rope[dName], IO.int[number]], icon: DBIcons.GetIcon[iconName: dName, default: queryerIcon] ]; END; END; MultiDisplay: PROC[entities: LIST OF Entity, title: ROPE, icon: Icons.IconFlavor] = BEGIN v, lastButton: Viewer; v_ ViewerOps.CreateViewer[ flavor: $Container, info: [name: title, iconic: FALSE, icon: icon], paint: FALSE]; lastButton_ NutViewer.Initialize[v]; FOR elT: LIST OF Entity_ entities, elT.rest UNTIL elT=NIL DO e: Entity= elT.first; lastButton _ NutViewer.MakeButton[ q: DBQueue[], name: GetName[e], proc: ProcessSelection, data: e, sib: lastButton, newLine: TRUE]; ENDLOOP; ViewerOps.PaintViewer[v, all] END; ProcessSelection: Menus.MenuProc = BEGIN viewer: ViewerClasses.Viewer _ NARROW[parent]; IF shift THEN TiogaOps.InsertRope[Rope.Substr[viewer.name, Rope.Find[viewer.name, ":"]+2]] ELSE BEGIN e: Entity_ V2E[clientData ! SafeStorage.NarrowRefFault => GO TO NotEntity]; FOR viewer _ viewer, viewer.parent UNTIL viewer.parent=NIL DO ENDLOOP; [] _ Nut.Display[eName: DB.NameOf[e], domain: DB.NameOf[DB.DomainOf[e]], segment: Nut.GetNutInfo[viewer].segment, parent: DefaultNutUtilities.GetTopLevel[viewer] ]; EXITS NotEntity => NutViewer.Message[viewer, "Not an entity-valued field!"]; END; END; ClearProc: Menus.MenuProc = BEGIN -- Resets contents of queryer . viewer: Viewer = NARROW[parent]; dName: ROPE; seg: Segment; d: Domain; al: AttributeList; [seg, dName,] _ Nut.GetNutInfo[viewer]; d _ DeclareDomain[dName, seg]; al _ DB.GetDomainRefAttributes[d]; InputFocus.SetInputFocus[]; -- kill the caret viewer.child _ NIL; TuplesEditor.ResetTuples[viewer]; ViewerOps.PaintViewer[viewer, $client]; [] _ TuplesEditor.DisplayTuples[NIL, al, viewer]; Menus.SetGuarded[ Menus.FindEntry[viewer.menu, "Clear"], FALSE ]; END; Menus.AppendMenuEntry[ displayerMenu, MakeMenuEntry[DBQueue[], "Edit", EditProc]]; Menus.AppendMenuEntry[ displayerMenu, MakeMenuEntry[DBQueue[], "Freeze", FreezeProc]]; Menus.AppendMenuEntry[ displayerMenu, MakeMenuEntry[DBQueue[], "Paste", PasteNameProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "Freeze", FreezeProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "Paste", PasteNameProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "Reset", ResetProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "Save", SaveProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "Rename", RenameProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "Merge", MergeProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "EraseAll", EraseAllProc]]; Menus.AppendMenuEntry[ editorMenu, MakeMenuEntry[DBQueue[], "AddSelected", AddProc]]; Menus.AppendMenuEntry[ queryerMenu, MakeMenuEntry[DBQueue[], "Query", QueryProc]]; Menus.AppendMenuEntry[ queryerMenu, MakeMenuEntry[DBQueue[], "Clear", ClearProc]]; Nut.Register[ NIL, NIL, DefaultDisplay, DefaultEdit, DefaultQuery ]; END. Change log [since copied some of this code into Walnut]: Cattell March 18, 1982 1:48 pm: Palm updates Cattell April 6, 1983 11:17 am: re-insert default displayer from old NutViewerDefaultImpl: Jim's editor is now default editor, old displayer is default displayer. No default queryer yet. Use VTables for the BuildTupleWindowButtons. Cattell April 7, 1983 11:58 am: various fixes everywhere. Cattell April 15, 1983 11:41 am: added Rename, Merge, EraseAll, etc. Not all checked yet. Changed "Remove" to EraseAll, as it erases all rather than what a user might think it does, i.e. removing one of the related entities. Cattell May 30, 1983 4:15 pm: added message subwindow to editor, fixed up icon for queryer, fixed some error conditions in editor, etc. Cattell June 22, 1983 3:49 pm: bug in RemoveSpecialAttributesFrom Cattell July 5, 1983 5:17 pm: fixed NutImpl and all procs to uniformly use a $NutType, $DomainName, $EntityName, and $Segment prop associated with all nut viewers. Butler June 26, 1984: Minor changes due to reorganization of Nut. Defaults now register with Nut instead of Nut knowing about them. vFile: NutDefaultImpl.mesa Contents: Implementation of the Default Create, Display, Edit, and Query windows. Last edited by: Willie-Sue on: January 21, 1983 8:57 am Cattell on: January 13, 1984 6:12 pm: removed Finch stuff Donahue on: July 13, 1984 12:06:20 pm PDT Butler on: August 16, 1984 11:05:38 am PDT Table of contents [use find command to locate]: Default Editor *** Default Displayer *** Default Queryer *** Default Editor ************************************************************ this procedure will return either the entity or the entity name for the viewer if the segment in which the entity would live is not currently open Resets contents of editor to its state before edits started. Invoked when hit the "Save" button on an editor: makes edits and then turns into displayer. Replace editor with displayer iff there were no error messages Invoked when hit the "Merge" button. Is supposed to copy all of the relationships connected with this entity to the entity in the same domain with the selected name, then delete the existing entity if any. -- looks like AddProc is for adding icons to the related entities list -------------------------- need to xreate a viewer Default Displayer ************************************************************ Overflow not yet implemented... Creates one line of buttons on the screen, for one database tuple Removes the "*" and "note" attributes that will be displayed in the later sections Invoked when hit the "Edit" button on the default displayer. Should replace the displayer viewer with an editor viewer. Default Queryer ************************************************************ Invoked when hit the "Query" button on an editor: makes new displayer for entities satisfying the query, if there are any. Processes a button press on a displayer button. If the shift key is held down, we stuff the contents of the button as text at the input point; else we display the entity. Insert the part of the string after the attribute name and ":" (entity name or other string) Find the top level viewer to pass off to the display proc Start Code ************************************************************ ÊW˜Jšœ™JšœQ™Qšœ™Jšœ'™'Jšœ9™9Jšœ)™)Jšœ*™*J˜—šœ/™/Jšœ™Jšœ™Jšœ™J˜J˜—šÏk ˜ Jšœœ˜J˜J˜ Jšœ˜Jšœœ ˜Jšœœ˜&Jšœ˜J˜Jšœœ˜*Jšœ œ˜!Jšœ˜JšœœF˜QJ˜ J˜Jšœ ˜ J˜J˜ J˜Jšœ œ˜#Jšœ œ˜J˜ J˜ J˜ J˜J˜ J˜J˜—šœœ˜š˜Jšœœ5œ˜MJšœ8˜8Jšœ/˜/—šœ˜J˜——Jšœœœ˜(J˜Jšœœ˜$J˜J˜JšœK™KJ˜J˜J˜,J˜šœU™UJšœ<™˜JJ˜9Jšœ9œ˜?Jšœ>™>šœ˜J˜G—šœ˜ J˜WJ˜RJšœ˜—Jšœ˜—Jšœ˜J˜J˜——˜š˜Jšœ\™\JšœY™YJšœ™Jšœœ ˜ J˜ J˜ Jšœœ˜ Jšœœ˜ J˜ J˜Jšœ œ&˜5J˜-Jšœœ˜!Jš œœ œœœœœ ˜OJš œœœœœ˜Fšœœ˜J˜2—šœœ œ˜J˜?—šœœ œ˜J˜<—šœœ˜Jšœ%˜%J˜ ˜J˜S—JšœL˜LJ˜Cšœ5˜:Jšœ<œ˜?—JšœŸ;˜PJ˜WJ˜RJšœ˜—Jšœ˜—J˜J˜—˜šœœ œ˜3Jšœœ4œ˜W—Jšœœ ˜ Jšœ ˜ Jšœ ˜ Jšœœ˜ Jšœœ˜ Jšœ ˜ Jšœ œ&˜3J˜,Jšœœ˜!Jšœœ˜"šœœ˜J˜-—šœœ œ˜J˜;—šœ˜Jšœ˜J˜0Jšœ&˜&J˜:J˜)—J˜J˜J˜—˜ Jšœœ ˜ Jšœ ˜ Jšœ ˜ Jšœœ˜ Jšœœ˜ Jšœ ˜ J˜,Jšœœ˜"Jš œœœœœ˜FJšœœœœ˜Jšœ˜J˜ J˜J˜—JšœÏbœ1™Fšœœ˜#Jšœœ ˜ Jšœ!˜!J˜3J˜šœ œ˜Jšœ1œ˜9—J˜4J˜-Jšœ˜J˜J˜—Jšœ™J˜šžœœœ˜9J˜ Jšœœœœ˜>J˜J˜—šœ œ˜!šœ˜ Jšœ œ ˜.Jšœœœ(˜3Jšœ™Jšœœ˜ J˜J˜%J˜$Jšœ œ˜J˜!Jšœ-˜-JšœN˜NJšœ˜ Jšœ˜J˜J˜J˜J˜——JšœN™NJ˜J˜J˜/J˜J˜šœœ˜$šœ˜ J˜Jšœœ œ ˜1Jšœœ œ ˜1J˜J˜'J˜6JšœWœ˜]J˜!Jšœ˜ Jšœ˜J˜——J˜šžœœ%œ ˜TJš˜J˜J˜ J˜J˜J˜J˜Jšœ%œ˜EJ˜$šœœœ˜+Jšœ˜Jšœ˜Jšœœœ˜Jšœ)˜)Jšœœ˜4šœ'œ˜Išœ˜%šœ0˜0JšœE˜E—Jšœ9˜9Jš˜——š˜Jšœ4˜4Jšœ˜—Jš˜—Jšœ ˜Jšœ˜J˜J˜—šžœœ=˜YJšœ™J˜;J˜J˜—šžœœ˜JšœE˜EJšœœœœ˜9Jšœ˜J˜JšœA™AJšœ œ˜Jšœ-œœ˜TJšœ˜Jšœœ'˜<šœ˜˜7Jšœ#œ˜)——Jšœ˜šœ"œœ˜5J˜šœœŸ ˜:˜šœ?˜?JšœB˜BJšœœ!œ˜6———Jšœ˜—Jšœ˜#Jšœ˜J˜—šž œœœ ˜9š˜Jšœœ ˜Jšœ.˜.Jšœ˜Jšœ˜Jšœ˜Jšœ#˜#Jšœ˜ Jšœ˜——˜J˜—šžœœ˜#Jš œœœœœœ˜IJšœR™RJš œœ œœ œ˜@J˜4J˜LJ˜LJ˜7J˜LJ˜ šœœœ˜J˜U—Jšœœœ+˜=Jšœ˜ J˜J˜J˜—˜š˜Jšœ<™Jšœœ3˜>J˜&Jšœœ˜Jšœœœ2˜Ašœœ˜J˜/—š œœ œœ˜"J˜@J˜^Jš˜—šœ˜ J˜L˜ J˜Jšœœ!œœ˜JJ˜?—Jšœ˜—Jšœ˜—J˜J˜J˜—š ž œœ œœœ˜SJšœ˜˜Jšœ0œœ˜R—J˜$š œœœœœ˜—˜J˜:—˜J˜8—˜J˜<—˜J˜:—˜J˜@—˜J˜>J˜—˜J˜;—šœT˜TJ˜—Jšœœœ.˜DJ˜J˜Jšœ˜J˜J˜8J˜J˜,J˜J˜éJ˜J˜9J˜J˜âJ˜J˜‡J˜J˜AJ˜J˜£J˜J˜J˜GJ˜&—…—=ÎU›