DIRECTORY CIFS USING [Error, Open, OpenFile, Close, GetPathname, read], Menus USING [Menu, MenuEntry, MenuProc, SetLine], MessageWindow USING [Append, Blink, Clear], NodeProps USING [GetProp, PutProp, Register, NullRead, NullWrite, NullCopy], Process USING [Detach], Rope USING [Concat, Equal, Fetch, Find, ROPE, Size, Substr], RopeEdit USING [BlankChar, IllegalChar], RTMiniModel USING [ImplementorName], TextEdit USING [Size], TextNode USING [FirstChild, LocNumber, Location, LocWithin, NarrowToTextNode, nullLocation, Offset, pZone, Ref, RefTextNode, Root], TEditDisplay USING [EstablishLine], TEditDocument USING [LineTableRec, maxClip, Selection, SpinAndLock, TEditDocumentData, Unlock], TEditDocumentPrivate, TEditInput USING [FreeTree], TEditInputOps USING [WaitForInsertToFinish], TEditOps, TEditProfile USING [DefaultMenuChoice, menu1, menu2, menu3, openFirstLevelOnly, sourceExtensions, implExtensions], TEditSelection USING [FindRope, LockSel, MakeSelection, pSel, sSel, fSel, UnlockSel], ViewerOps USING [AddProp, CloseViewer, ComputeColumn, CreateViewer, DestroyViewer, EstablishViewerPosition, FetchProp, MoveBelowViewer, OpenIcon, PaintHint, PaintViewer, SaveViewer, SetMenu], ViewerClasses USING [GetProc, Viewer, ViewerClass, ViewerClassRec], ViewerTools USING [GetContents, GetSelectionContents, SelPos, SelPosRec, SetSelection], VirtualDesktops USING [FindViewer]; TEditDocuments2Impl: CEDAR MONITOR IMPORTS CIFS, Menus, MessageWindow, NodeProps, Process, Rope, RopeEdit, RTMiniModel, TEditDocument, TEditDocumentPrivate, TextEdit, TextNode, TEditDisplay, TEditInput, TEditInputOps, TEditProfile, TEditSelection, ViewerOps, ViewerTools, VirtualDesktops EXPORTS TEditDocument, TEditDocumentPrivate, TEditOps SHARES ViewerClasses = BEGIN OPEN Rope, TEditDocument, TEditDocumentPrivate, ViewerClasses; ForceInitialCaret: PROC [viewer: Viewer] = INLINE {ViewerTools.SetSelection[viewer, initialCaret]}; initialCaret: ViewerTools.SelPos _ NEW[ViewerTools.SelPosRec]; CancelLinks: PUBLIC PROC [viewer: Viewer] = BEGIN ForgetViewer[viewer]; IF viewer.link.link=viewer THEN BEGIN viewer.link.link _ NIL; ViewerOps.PaintViewer[viewer.link, caption]; END ELSE FOR v: Viewer _ viewer.link.link, v.link UNTIL v.link=viewer DO REPEAT FINISHED => v.link _ viewer.link; ENDLOOP; viewer.link _ NIL; END; lastRoot: TextNode.Ref; lastViewer: ViewerClasses.Viewer; RecordViewerForRoot: PUBLIC ENTRY PROC [viewer: ViewerClasses.Viewer, root: TextNode.Ref] = { ENABLE UNWIND => NULL; RecordViewerForRootI[viewer, root] }; RecordViewerForRootI: INTERNAL PROC [viewer: ViewerClasses.Viewer, root: TextNode.Ref] = { NodeProps.PutProp[root,$Viewer,viewer]; IF root = lastRoot THEN lastViewer _ viewer; -- keep the cache up to date }; ForgetViewer: PUBLIC ENTRY PROC [viewer: ViewerClasses.Viewer] = { ENABLE UNWIND => NULL; tdd: TEditDocument.TEditDocumentData = NARROW[viewer.data]; root: TextNode.Ref; IF tdd=NIL THEN RETURN; root _ tdd.text; IF GetViewerForRootI[root] # viewer THEN RETURN; IF viewer.link # NIL THEN { -- change to a linked viewer RecordViewerForRootI[viewer.link,root]; RETURN }; RecordViewerForRootI[NIL,root] }; GetViewerForRoot: PUBLIC ENTRY PROC [root: TextNode.Ref] RETURNS [viewer: ViewerClasses.Viewer] = { ENABLE UNWIND => NULL; RETURN [GetViewerForRootI[root]] }; GetViewerForRootI: INTERNAL PROC [root: TextNode.Ref] RETURNS [viewer: ViewerClasses.Viewer] = { IF root = NIL THEN RETURN [NIL]; IF root = lastRoot THEN RETURN [lastViewer]; lastRoot _ root; RETURN [lastViewer _ NARROW[NodeProps.GetProp[root,$Viewer]]] }; LookupDirectoryName: PROC [file: Rope.ROPE] RETURNS [fullName: Rope.ROPE] = BEGIN fh: CIFS.OpenFile _ CIFS.Open[file, CIFS.read]; fullName _ CIFS.GetPathname[fh]; CIFS.Close[fh]; IF fullName=NIL THEN fullName _ file; -- temp hack until CIFS bug is fixed. IF Rope.Find[fullName,"/local/",0,FALSE]=0 THEN -- delete it from start of name fullName _ Rope.Substr[fullName, Rope.Size["/local/"]]; END; GetDirectoryName: PROC [file: Rope.ROPE] RETURNS [directoryName: Rope.ROPE, new: BOOL] = { new _ FALSE; IF Rope.Size[file]=0 THEN RETURN [NIL,TRUE]; directoryName _ LookupDirectoryName[file ! CIFS.Error => {directoryName _ file; new _ TRUE; CONTINUE}] }; PreStore: PUBLIC Menus.MenuProc = { -- called when Store menu item becomes unguarded new: BOOL; fileName: Rope.ROPE _ ViewerTools.GetSelectionContents[]; IF Rope.Size[fileName]=0 THEN {PleaseSelectFileName[]; RETURN}; IF ~CheckFileName[fileName] THEN RETURN; [fileName, new] _ GetDirectoryName[fileName]; MessageWindow.Append[Rope.Concat["Confirm Store to file: ", Rope.Concat[fileName, IF new THEN " [New File]" ELSE " [Old File]"]], TRUE] }; StoreFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = { DoStoreFile[parent,NIL] }; DoStoreFile: PUBLIC PROC [parent: ViewerClasses.Viewer, fileName: Rope.ROPE _ NIL] = BEGIN new, linked: BOOL; tdd: TEditDocumentData; IF fileName=NIL THEN fileName _ ViewerTools.GetSelectionContents[]; IF Rope.Size[fileName]=0 THEN {PleaseSelectFileName[]; RETURN}; IF ~CheckFileName[fileName] THEN RETURN; [fileName, new] _ GetDirectoryName[fileName]; IF VirtualDesktops.FindViewer[fileName].viewer # NIL THEN { -- already loaded MessageWindow.Append[ Rope.Concat[fileName, " is already in a viewer! Cannot Store to that name."], TRUE]; MessageWindow.Blink; RETURN }; tdd _ NARROW[parent.data]; IF tdd = NIL THEN RETURN; [] _ SpinAndLock[tdd, "DoStoreFile"]; IF parent.file # NIL THEN SaveLoadHistory[parent]; IF linked _ (parent.link#NIL) THEN CancelLinks[parent]; -- remove viewer from link chain parent.name _ parent.file _ fileName; NodeProps.PutProp[tdd.text, $FileCreateDate, NIL]; -- remove so Save won't test Unlock[tdd]; ViewerOps.SaveViewer[parent]; IF linked THEN { -- copy tdd.text data structure loc: TextNode.Offset; KillSelections[parent]; [] _ SpinAndLock[tdd, "DoStoreFile2"]; loc _ TextNode.LocNumber[tdd.lineTable.lines[0].pos]; tdd.text _ NIL; -- so InitViewerDoc won't free it InitViewerDoc[parent, NIL]; IF ~PositionViewer[parent,TextNode.LocWithin[tdd.text,loc],all] THEN TRUSTED {Process.Detach[FORK PaintAndRemember[parent]]}; Unlock[tdd] }; END; KillSelections: PROC [parent: ViewerClasses.Viewer] = { OPEN TEditSelection; IF pSel # NIL AND pSel.viewer = parent THEN MakeSelection[selection: primary]; IF sSel # NIL AND sSel.viewer = parent THEN MakeSelection[selection: secondary]; IF fSel # NIL AND fSel.viewer = parent THEN MakeSelection[selection: feedback] }; EmptyViewer: PUBLIC PROC [parent: ViewerClasses.Viewer] = BEGIN WITH parent.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { TEditSelection.LockSel[primary, "EmptyViewer"]; { ENABLE UNWIND => TEditSelection.UnlockSel[primary]; prop: REF LoadHistory; [] _ SpinAndLock[tdd, "EmptyViewer"]; KillSelections[parent]; SaveLoadHistory[parent]; prop _ NARROW[ViewerOps.FetchProp[parent, $LoadHistory]]; -- hang onto it IF parent.link#NIL THEN CancelLinks[parent] ELSE IF parent.newVersion AND ~parent.saveInProgress AND parent.file # NIL THEN RecordUnsavedDocument[parent.file, tdd.text] ELSE TEditInput.FreeTree[tdd.text]; parent.name _ "No Name"; parent.file _ NIL; parent.newVersion _ parent.newFile _ FALSE; tdd.text _ NIL; -- so InitViewerDoc won't free it InitViewerDoc[parent,NIL]; Unlock[tdd]; ClearPositionHistory[parent]; ViewerOps.AddProp[parent, $LoadHistory, prop]; -- restore file history ViewerOps.PaintViewer[parent, all]; ForceInitialCaret[parent] }; TEditSelection.UnlockSel[primary]; }; ENDCASE; END; PleaseSelectFileName: PROC = { MessageWindow.Append["Please select file name.", TRUE]; MessageWindow.Blink[] }; CheckFileName: PROC [directoryName: Rope.ROPE] RETURNS [BOOLEAN] = { FOR i:NAT IN [0..Rope.Size[directoryName]) DO char: CHAR _ Rope.Fetch[directoryName, i]; IF RopeEdit.BlankChar[char] OR RopeEdit.IllegalChar[char] THEN { MessageWindow.Append["Illegal file name", TRUE]; MessageWindow.Blink[]; RETURN [FALSE] }; ENDLOOP; RETURN [TRUE] }; UnknownFile: PROC [directoryName: Rope.ROPE] = { MessageWindow.Append[directoryName, TRUE]; MessageWindow.Append[" not found."]; MessageWindow.Blink[]; RETURN}; CheckName: PROC [name, ext: Rope.ROPE] RETURNS [file: Rope.ROPE, fileExists: BOOL] = { fileExists _ TRUE; file _ Rope.Concat[name, ext]; file _ LookupDirectoryName[file ! CIFS.Error => { fileExists _ FALSE; CONTINUE }] }; GetNameAndSearchRope: PROC [ sel: Rope.ROPE, fileNameProcViewer: ViewerClasses.Viewer] RETURNS [file, search: Rope.ROPE] = { name: Rope.ROPE; dot, extSize: INT; fileExists, standard, noDot: BOOL _ FALSE; MessageWindow.Append[Rope.Concat["Directory lookup for ", sel], TRUE]; [file, fileExists] _ CheckName[sel, NIL]; IF fileExists THEN RETURN; IF (dot _ Rope.Find[sel, "."]) < 0 THEN { -- no dot in selection FOR lst: LIST OF Rope.ROPE _ TEditProfile.sourceExtensions, lst.rest UNTIL lst=NIL DO [file, fileExists] _ CheckName[sel, lst.first]; IF fileExists THEN RETURN; ENDLOOP; noDot _ TRUE; name _ sel; search _ NIL } ELSE { name _ Rope.Substr[sel, 0, dot]; -- the text before the "." search _ Rope.Substr[sel, dot+1]; -- the text after the "." extSize _ Rope.Size[search]+1; FOR lst: LIST OF Rope.ROPE _ TEditProfile.sourceExtensions, lst.rest UNTIL lst=NIL DO IF Rope.Size[lst.first]=extSize AND Rope.Find[lst.first, search, 1, FALSE]=1 THEN { standard _ TRUE; EXIT }; -- this is one of the standard extensions ENDLOOP; }; IF fileNameProc # NIL THEN { srch: Rope.ROPE; [file, srch] _ fileNameProc[sel, fileNameProcViewer]; IF file # NIL THEN RETURN [file, srch] }; IF ~standard AND ~noDot THEN -- try from the list of standard extensions FOR lst: LIST OF Rope.ROPE _ TEditProfile.sourceExtensions, lst.rest UNTIL lst=NIL DO [file, fileExists] _ CheckName[name, lst.first]; IF fileExists THEN RETURN; ENDLOOP; file _ sel; search _ NIL }; fileNameProc: PROC [Rope.ROPE, ViewerClasses.Viewer] RETURNS [fileName: Rope.ROPE, search: Rope.ROPE] _ NIL; RegisterFileNameProc: PUBLIC PROC [proc: PROC [Rope.ROPE, ViewerClasses.Viewer] RETURNS [fileName: Rope.ROPE, search: Rope.ROPE]] = { fileNameProc _ proc }; GetImplNameAndSearchRope: PROC [sel: Rope.ROPE] RETURNS [impl, search: Rope.ROPE] = { name, defsName: Rope.ROPE; dot: INT; fileExists: BOOL; IF (dot _ Rope.Find[sel, "."]) < 0 THEN { defsName _ sel; search _ NIL } ELSE { defsName _ Rope.Substr[sel, 0, dot]; search _ Rope.Substr[sel, dot+1] }; IF Rope.Size[search] > 0 THEN { MessageWindow.Append[Rope.Concat["Model lookup for implementor of ", search], TRUE]; name _ RTMiniModel.ImplementorName[defsName, search] }; IF name=NIL THEN name _ Rope.Concat[defsName, "Impl"]; MessageWindow.Append[Rope.Concat["Directory lookup for ", name], TRUE]; FOR lst: LIST OF Rope.ROPE _ TEditProfile.implExtensions, lst.rest UNTIL lst=NIL DO [impl, fileExists] _ CheckName[name, lst.first]; IF fileExists THEN RETURN; ENDLOOP; RETURN [name, NIL] }; DoSearch: PROC [v: Viewer, search: Rope.ROPE] = { -- search for definition tdd: TEditDocument.TEditDocumentData _ NARROW[v.data]; loc: TextNode.Location; IF tdd = NIL OR Rope.Size[search] = 0 THEN RETURN; -- forget it IF (loc _ TextNode.LocWithin[tdd.text,0]) # tdd.lineTable.lines[0].pos THEN { TEditDisplay.EstablishLine[tdd, loc]; ViewerOps.PaintViewer[v, client] }; -- always search from start TEditSelection.FindRope[ viewer: v, rope: search, case: FALSE, word: TRUE, def: TRUE, id: feedback]; }; CopyPositionHistory: PUBLIC PROC [from, to: Viewer] = { old: REF PositionHistory _ NARROW[ViewerOps.FetchProp[from, $PositionHistory]]; new: REF PositionHistory _ NARROW[ViewerOps.FetchProp[to, $PositionHistory]]; IF old=NIL THEN RETURN; IF new=NIL THEN { new _ TextNode.pZone.NEW[PositionHistory]; ViewerOps.AddProp[to, $PositionHistory, new] }; new^ _ old^; }; ClearPositionHistory: PROC [viewer: Viewer] = { prop: REF PositionHistory _ NARROW[ViewerOps.FetchProp[viewer, $PositionHistory]]; IF prop = NIL THEN RETURN; prop.pos _ prop.prev _ TextNode.nullLocation; }; RememberCurrentPosition: PUBLIC PROC [viewer: Viewer] = { tdd: TEditDocument.TEditDocumentData _ NARROW[viewer.data]; prop: REF PositionHistory _ NARROW[ViewerOps.FetchProp[viewer, $PositionHistory]]; loc: TextNode.Location; IF tdd=NIL THEN RETURN; IF prop = NIL THEN { prop _ TextNode.pZone.NEW[PositionHistory]; ViewerOps.AddProp[viewer, $PositionHistory, prop] }; [] _ SpinAndLock[tdd, "RememberCurrentPosition"]; loc _ tdd.lineTable.lines[0].pos; Unlock[tdd]; IF loc = prop.pos THEN RETURN; prop.prev _ prop.pos; prop.pos _ loc }; CheckPosition: PROC [viewer: Viewer, loc: TextNode.Location] RETURNS [good: BOOLEAN, goodloc: TextNode.Location] = { root, node: TextNode.Ref; t1: TextNode.RefTextNode; tdd: TEditDocument.TEditDocumentData; IF viewer=NIL OR viewer.destroyed OR (node _ loc.node)=NIL THEN GOTO Failed; IF (tdd _ NARROW[viewer.data]) = NIL THEN GOTO Failed; IF (root _ tdd.text)=NIL THEN GOTO Failed; IF TextNode.Root[node] # root THEN GOTO Failed; -- make sure still in the tree IF (t1 _ TextNode.NarrowToTextNode[node])=NIL OR loc.where NOT IN [0..TextEdit.Size[t1]] THEN RETURN [TRUE, [node,0]]; RETURN [TRUE,loc]; EXITS Failed => RETURN [FALSE, TextNode.nullLocation]; }; PositionViewer: PUBLIC PROC [viewer: Viewer, loc: TextNode.Location, hint: ViewerOps.PaintHint _ client] RETURNS [ok: BOOLEAN] = { tdd: TEditDocument.TEditDocumentData _ NARROW[viewer.data]; node: TextNode.RefTextNode; [ok, loc] _ CheckPosition[viewer, loc]; IF tdd = NIL OR ~ok THEN RETURN; RememberCurrentPosition[viewer]; IF (node _ TextNode.NarrowToTextNode[loc.node]) # NIL THEN { -- backup to line start where: INT _ MAX[0, MIN[loc.where, TextEdit.Size[node]-1]]; backStop: INT _ MAX[0, where-300]; UNTIL where<=backStop OR Rope.Fetch[node.rope, where-1]=15C DO where _ where - 1; ENDLOOP; loc.where _ where }; TEditDisplay.EstablishLine[tdd, loc]; TRUSTED {Process.Detach[FORK ViewerOps.PaintViewer[viewer, hint ! ABORTED => CONTINUE]]}; }; LoadHistory: TYPE = RECORD [ name: Rope.ROPE, place: TextNode.Offset ]; CopyLoadHistory: PUBLIC PROC [from, to: Viewer] = { old: REF LoadHistory _ NARROW[ViewerOps.FetchProp[from, $LoadHistory]]; new: REF LoadHistory _ NARROW[ViewerOps.FetchProp[to, $LoadHistory]]; IF old=NIL THEN RETURN; IF new=NIL THEN { new _ TextNode.pZone.NEW[LoadHistory]; ViewerOps.AddProp[to, $LoadHistory, new] }; new^ _ old^; }; LoadPreviousFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = BEGIN DoLoadPreviousFile[parent, FALSE, FALSE]; END; OpenPreviousFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = BEGIN DoLoadPreviousFile[parent, TRUE, FALSE]; END; CloseAndOpenPreviousFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = BEGIN DoLoadPreviousFile[parent, TRUE, TRUE]; END; PreLoadPrevious: PUBLIC Menus.MenuProc = { viewer: ViewerClasses.Viewer = NARROW[parent]; tdd: TEditDocumentData; prop: REF LoadHistory; propName: Rope.ROPE; tdd _ NARROW[viewer.data]; IF tdd = NIL THEN RETURN; [] _ SpinAndLock[tdd, "PreLoadPrevious"]; -- delay until after other op completes prop _ NARROW[ViewerOps.FetchProp[viewer, $LoadHistory]]; Unlock[tdd]; IF prop = NIL OR Rope.Equal[prop.name, viewer.file, FALSE] THEN { MessageWindow.Append["No record of previous file loaded in this viewer",TRUE]; MessageWindow.Blink[]; RETURN }; propName _ prop.name; IF ~CheckFileName[propName] THEN RETURN; MessageWindow.Append[clearFirst: TRUE, message: Rope.Concat[propName, " ~ Click LEFT to load, MIDDLE for new, RIGHT for close & new"]]; }; DoLoadPreviousFile: PROC [parent: ViewerClasses.Viewer, open, close: BOOL] = BEGIN tdd: TEditDocumentData; prop: REF LoadHistory; propName: Rope.ROPE; propPlace: TextNode.Offset; tdd _ NARROW[parent.data]; IF tdd = NIL THEN RETURN; [] _ SpinAndLock[tdd, "DoLoadPreviousFile"]; -- delay until after other op completes prop _ NARROW[ViewerOps.FetchProp[parent, $LoadHistory]]; Unlock[tdd]; IF prop = NIL OR Rope.Equal[prop.name, parent.file, FALSE] THEN { MessageWindow.Append["No record of previous file loaded in this viewer",TRUE]; MessageWindow.Blink[]; RETURN }; propName _ prop.name; propPlace _ prop.place; IF ~CheckFileName[propName] THEN RETURN; IF open AND ~close THEN [] _ DoOpen[propName, parent, propPlace] ELSE [] _ DoLoad[parent, propName, close, propPlace]; END; CheckAnonymous: PROC [parent: ViewerClasses.Viewer, txt: Rope.ROPE] RETURNS [BOOLEAN] = { IF Rope.Size[txt]=0 THEN { MessageWindow.Append["Enter a file name.",TRUE]; MessageWindow.Blink[]; RETURN[FALSE]}; IF ~CheckFileName[txt] THEN RETURN[FALSE]; RETURN [TRUE]; }; CheckNoName: PROC [parent: ViewerClasses.Viewer] RETURNS [BOOLEAN] = { IF ~Rope.Equal[parent.name, "No Name"] THEN { MessageWindow.Append["Not a \"No Name\" viewer",TRUE]; MessageWindow.Blink[]; RETURN [FALSE]}; RETURN [TRUE]; }; AnonymousLoadFile: PUBLIC PROC [ parent: ViewerClasses.Viewer, fileNameProcViewer: ViewerClasses.Viewer _ NIL] = { txt: Rope.ROPE; IF ~CheckNoName[parent] THEN RETURN; TEditInputOps.WaitForInsertToFinish[]; txt _ ViewerTools.GetContents[parent]; IF ~CheckAnonymous[parent, txt] THEN RETURN; [] _ LoadAndSearch[parent, txt, FALSE, fileNameProcViewer]; }; LoadAndSearch: PROC [ parent: ViewerClasses.Viewer, txt: Rope.ROPE, close: BOOL _ FALSE, fileNameProcViewer: ViewerClasses.Viewer _ NIL] RETURNS [viewer: ViewerClasses.Viewer] = { file, search: Rope.ROPE; IF fileNameProcViewer=NIL THEN fileNameProcViewer _ parent; [file, search] _ GetNameAndSearchRope[txt, fileNameProcViewer]; IF (viewer _ DoLoad[parent, file, close]) # NIL THEN DoSearch[viewer, search]; }; AnonymousLoadImplFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = { txt: Rope.ROPE; IF ~CheckNoName[parent] THEN RETURN; TEditInputOps.WaitForInsertToFinish[]; txt _ ViewerTools.GetContents[parent]; IF ~CheckAnonymous[parent, txt] THEN RETURN; [] _ LoadImplAndSearch[parent, txt]; }; LoadImplAndSearch: PROC [parent: ViewerClasses.Viewer, txt: Rope.ROPE, close: BOOL _ FALSE] RETURNS [viewer: Viewer] = { impl, search: Rope.ROPE; [impl, search] _ GetImplNameAndSearchRope[txt]; IF (viewer _ DoLoad[parent, impl, close]) # NIL THEN DoSearch[viewer, search]; }; LoadFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = { [] _ DoLoadFile[parent, NIL, FALSE] }; DoLoadFile: PUBLIC PROC [ parent: ViewerClasses.Viewer, fileName: ROPE _ NIL, close: BOOL _ FALSE, fileNameProcViewer: ViewerClasses.Viewer _ NIL] RETURNS [viewer: ViewerClasses.Viewer] = BEGIN tdd: TEditDocumentData; IF fileName=NIL THEN fileName _ ViewerTools.GetSelectionContents[]; tdd _ NARROW[parent.data]; IF tdd = NIL THEN RETURN; [] _ SpinAndLock[tdd, "DoLoadFile"]; Unlock[tdd]; -- let other op finish first IF ~PreLoadCheck[parent, fileName] THEN RETURN; viewer _ LoadAndSearch[parent, fileName, close, fileNameProcViewer]; END; LoadImplFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = { [] _ DoLoadImplFile[parent, NIL] }; DoLoadImplFile: PUBLIC PROC [ parent: ViewerClasses.Viewer, fileName: ROPE _ NIL, close: BOOL _ FALSE] RETURNS [viewer: Viewer] = BEGIN tdd: TEditDocumentData; IF fileName=NIL THEN fileName _ ViewerTools.GetSelectionContents[]; tdd _ NARROW[parent.data]; IF tdd = NIL THEN RETURN; [] _ SpinAndLock[tdd ,"DoLoadImplFile"]; Unlock[tdd]; -- let other op finish first IF ~PreLoadCheck[parent, fileName] THEN RETURN; viewer _ LoadImplAndSearch[parent, fileName, close]; END; PreLoadCheck: PROC [parent: Viewer, sel: Rope.ROPE] RETURNS [BOOLEAN] = { IF Rope.Size[sel]=0 THEN {PleaseSelectFileName[]; RETURN[FALSE]}; IF ~CheckFileName[sel] THEN RETURN[FALSE]; RETURN [TRUE] }; AllocLoadHistory: PROC [viewer: Viewer] RETURNS [prop: REF LoadHistory] = { IF (prop _ NARROW[ViewerOps.FetchProp[viewer, $LoadHistory]]) # NIL THEN RETURN; prop _ TextNode.pZone.NEW[LoadHistory]; ViewerOps.AddProp[viewer, $LoadHistory, prop] }; SetLoadHistoryInfo: PROC [viewer: Viewer, prop: REF LoadHistory] = { tdd: TEditDocument.TEditDocumentData _ NARROW[viewer.data]; IF tdd = NIL THEN RETURN; prop.name _ viewer.file; prop.place _ TextNode.LocNumber[tdd.lineTable.lines[0].pos] }; SetLoadHistory: PROC [parent, viewer: Viewer] = { prop: REF LoadHistory _ AllocLoadHistory[viewer]; SetLoadHistoryInfo[parent, prop] }; SaveLoadHistory: PROC [viewer: Viewer] = { prop: REF LoadHistory _ AllocLoadHistory[viewer]; SetLoadHistoryInfo[viewer, prop] }; DoLoad: PROC [viewer: Viewer, file: Rope.ROPE, close: BOOL _ FALSE, place: TextNode.Offset _ 0] RETURNS [Viewer] = BEGIN new: BOOLEAN _ FALSE; tdd: TEditDocument.TEditDocumentData; oldViewer, destroyViewer: Viewer; tddOld: TEditDocument.TEditDocumentData; clearMessage: BOOL _ TRUE; directoryName: Rope.ROPE; [directoryName,new] _ GetDirectoryName[file]; IF new THEN { UnknownFile[directoryName]; RETURN[NIL] }; IF Rope.Equal[directoryName,viewer.name] THEN { MessageWindow.Append[Rope.Concat[directoryName," is already loaded."],TRUE]; RETURN [viewer] }; MessageWindow.Append[Rope.Concat["Loading ", directoryName],TRUE]; KillSelections[viewer]; tdd _ NARROW[viewer.data]; IF tdd = NIL THEN RETURN [viewer]; [] _ SpinAndLock[tdd, "DoLoad"]; IF viewer.file # NIL THEN SaveLoadHistory[viewer]; IF viewer.link=NIL THEN { IF close THEN { Unlock[tdd]; viewer _ ReplaceByNewViewer[viewer]; RETURN [DoLoad[viewer, file, FALSE, place]] }; -- try again ForgetViewer[viewer]; -- remove this from the root => viewer mapping IF viewer.newVersion AND ~viewer.saveInProgress AND viewer.file # NIL THEN RecordUnsavedDocument[viewer.file, tdd.text] ELSE TEditInput.FreeTree[tdd.text] } ELSE CancelLinks[viewer]; viewer.name _ viewer.file _ NIL; [oldViewer, ----] _ VirtualDesktops.FindViewer[directoryName]; viewer.name _ viewer.file _ directoryName; viewer.newVersion _ viewer.newFile _ FALSE; IF oldViewer # NIL AND NOT oldViewer.destroyed AND (tddOld _ NARROW[oldViewer.data]) # NIL THEN { -- link them viewer.newVersion _ oldViewer.newVersion; viewer.newFile _ oldViewer.newFile; [] _ SpinAndLock[tddOld, "DoLoad"]; tdd.text _ tddOld.text; tdd.tsInfo _ tddOld.tsInfo; Unlock[tddOld]; tdd.lineTable.lines[0].pos _ [TextNode.FirstChild[tdd.text],0]; tdd.clipLevel _ maxClip; tdd.commentFilter _ includeComments; viewer.link _ oldViewer; IF oldViewer.link=NIL THEN { oldViewer.link _ viewer; ViewerOps.PaintViewer[oldViewer, caption] } ELSE FOR v: Viewer _ oldViewer.link, v.link UNTIL v.link=oldViewer DO REPEAT FINISHED => v.link _ viewer; ENDLOOP; MessageWindow.Append[Rope.Concat[directoryName," was already loaded."],TRUE]; clearMessage _ FALSE; FOR v: Viewer _ oldViewer, v.link UNTIL v.link=oldViewer DO IF v.iconic THEN { destroyViewer _ v; EXIT }; -- destroy an iconic viewer ENDLOOP } ELSE { root: TextNode.Ref _ FindUnsavedDocument[directoryName]; tdd.text _ NIL; -- so InitViewerDoc won't worry about freeing it IF root # NIL THEN { MessageWindow.Append[ Rope.Concat[directoryName," restored with previous unsaved edits."],TRUE]; MessageWindow.Blink[]; clearMessage _ FALSE }; InitViewerDoc[viewer, root]; viewer.newVersion _ root # NIL; viewer.newFile _ FALSE }; ClearPositionHistory[viewer]; IF ~PositionViewer[viewer,TextNode.LocWithin[tdd.text,place],all] THEN TRUSTED {Process.Detach[FORK PaintAndRemember[viewer ! ABORTED => CONTINUE]]}; Unlock[tdd]; IF destroyViewer # NIL THEN ViewerOps.DestroyViewer[destroyViewer]; IF clearMessage THEN MessageWindow.Clear[]; RETURN[viewer]; END; PaintAndRemember: PROC [viewer: ViewerClasses.Viewer] = { ViewerOps.PaintViewer[viewer,all]; RememberCurrentPosition[viewer] }; ReplaceByNewViewer: PROC [parent: ViewerClasses.Viewer] RETURNS [viewer: Viewer] = { KillSelections[parent]; viewer _ MakeNewViewer[parent, FALSE]; viewer.openHeight _ parent.openHeight; viewer.position _ parent.position; SetLoadHistory[parent, viewer]; ViewerOps.CloseViewer[viewer: parent, paint: FALSE]; ViewerOps.PaintViewer[parent, all]; -- paint the icon }; MakeNewViewer: PROC [parent: ViewerClasses.Viewer, paint: BOOL _ TRUE] RETURNS [viewer: Viewer] = { viewer _ ViewerOps.CreateViewer[flavor: $Text, info: [name: "No Name", column: IF parent=NIL THEN left ELSE parent.column, iconic: TRUE], paint: FALSE]; IF TEditProfile.openFirstLevelOnly THEN { tdd: TEditDocument.TEditDocumentData _ NARROW[viewer.data]; IF tdd # NIL THEN tdd.clipLevel _ 1 }; ViewerOps.OpenIcon[icon: viewer, paint: FALSE]; IF parent # NIL THEN { -- move above parent and copy menus ViewerOps.MoveBelowViewer[altered: viewer, static: parent, paint: FALSE]; ViewerOps.SetMenu[viewer, parent.menu, FALSE]; ViewerOps.EstablishViewerPosition[viewer, viewer.wx, viewer.wy, viewer.ww, viewer.wh]; } ELSE DefaultMenus[viewer]; IF paint THEN ViewerOps.ComputeColumn[viewer.column]; -- paints the column }; CloseAndNewViewer: PUBLIC PROC [parent: Viewer] = { [] _ DoCloseAndNewViewer[parent] }; DoCloseAndNewViewer: PUBLIC PROC [parent: ViewerClasses.Viewer] RETURNS [new: ViewerClasses.Viewer] = { TEditSelection.LockSel[primary, "DoCloseAndNewViewer"]; { ENABLE UNWIND => TEditSelection.UnlockSel[primary]; new _ ReplaceByNewViewer[parent]; ViewerOps.PaintViewer[new, all]; ForceInitialCaret[new] }; TEditSelection.UnlockSel[primary]; }; NewViewer: PUBLIC PROC [parent: ViewerClasses.Viewer] = { [] _ DoNewViewer[parent] }; DoNewViewer: PUBLIC PROC [parent: ViewerClasses.Viewer _ NIL] RETURNS [new: ViewerClasses.Viewer] = BEGIN TEditSelection.LockSel[primary, "DoCloseAndNewViewer"]; { ENABLE UNWIND => TEditSelection.UnlockSel[primary]; ForceInitialCaret[new _ MakeNewViewer[parent,TRUE]] }; TEditSelection.UnlockSel[primary]; END; CloseAndOpenFile: PUBLIC PROC [parent: Viewer, fileNameProcViewer: Viewer _ NIL] = { [] _ DoLoadFile[parent, NIL, TRUE, fileNameProcViewer] }; DoCloseAndOpenFile: PUBLIC PROC [parent: Viewer, fileName: ROPE _ NIL] RETURNS [viewer: Viewer] = { RETURN [DoLoadFile[parent, fileName, TRUE]] }; OpenFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = { [] _ DoOpenFile[NIL, parent] }; DoOpenFile: PUBLIC PROC [ fileName: ROPE _ NIL, parent, fileNameProcViewer: ViewerClasses.Viewer _ NIL] RETURNS [viewer: ViewerClasses.Viewer] = BEGIN file, search: Rope.ROPE; IF fileName=NIL THEN fileName _ ViewerTools.GetSelectionContents[]; IF ~PreOpenCheck[fileName] THEN RETURN; IF fileNameProcViewer=NIL THEN fileNameProcViewer _ parent; [file, search] _ GetNameAndSearchRope[fileName, fileNameProcViewer]; IF (viewer _ DoOpen[file,parent]) # NIL THEN DoSearch[viewer, search]; END; CloseAndOpenImplFile: PUBLIC PROC [parent: Viewer] = { [] _ DoCloseAndOpenImplFile[parent, NIL] }; DoCloseAndOpenImplFile: PUBLIC PROC [parent: Viewer, fileName: ROPE _ NIL] RETURNS [viewer: Viewer] = { RETURN [DoLoadImplFile[parent, fileName, TRUE]] }; OpenImplFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = BEGIN [] _ DoOpenImplFile[NIL, parent]; END; DoOpenImplFile: PUBLIC PROC [fileName: ROPE _ NIL, parent: ViewerClasses.Viewer _ NIL] RETURNS [viewer: Viewer] = BEGIN impl, search: Rope.ROPE; IF fileName=NIL THEN fileName _ ViewerTools.GetSelectionContents[]; IF ~PreOpenCheck[fileName] THEN RETURN; [impl, search] _ GetImplNameAndSearchRope[fileName]; IF (viewer _ DoOpen[impl,parent]) # NIL THEN DoSearch[viewer, search]; END; PreOpenCheck: PROC [sel: Rope.ROPE] RETURNS [BOOLEAN] = { IF Rope.Size[sel]=0 THEN {PleaseSelectFileName[]; RETURN[FALSE]}; IF ~CheckFileName[sel] THEN RETURN[FALSE]; RETURN [TRUE] }; DoOpen: PROC [file: Rope.ROPE, parent: Viewer, place: TextNode.Offset _ 0] RETURNS [viewer: Viewer] = BEGIN new: BOOLEAN _ FALSE; directoryName: Rope.ROPE; [directoryName,new] _ GetDirectoryName[file]; IF new THEN { UnknownFile[directoryName]; RETURN [NIL] }; viewer _ DoLoad[MakeNewViewer[parent,TRUE],directoryName,FALSE,place]; END; DefaultMenus: PUBLIC PROC [viewer: Viewer, paint: BOOL _ FALSE] = BEGIN menu: Menus.Menu _ viewer.menu; num: INTEGER _ 1; DoLine: PROC [which: TEditProfile.DefaultMenuChoice] = { entry: Menus.MenuEntry _ SELECT which FROM places => findMenu, levels => levelMenu, ENDCASE => NIL; IF entry = NIL THEN RETURN; Menus.SetLine[menu, num, entry]; num _ num+1 }; DoLine[TEditProfile.menu1]; DoLine[TEditProfile.menu2]; DoLine[TEditProfile.menu3]; ViewerOps.EstablishViewerPosition[viewer, viewer.wx, viewer.wy, viewer.ww, viewer.wh]; IF paint THEN ViewerOps.PaintViewer[viewer, all]; END; NodeProps.Register[$Viewer, NodeProps.NullRead, NodeProps.NullWrite, NodeProps.NullCopy]; NodeProps.Register[$FileCreateDate, NodeProps.NullRead, NodeProps.NullWrite, NodeProps.NullCopy]; NodeProps.Register[$FileExtension, NodeProps.NullRead, NodeProps.NullWrite, NodeProps.NullCopy]; END. ú-- TEditDocuments2Impl.mesa; Edited by Paxton on December 29, 1982 9:27 am -- Edited by McGregor on September 10, 1982 1:53 pm Last Edited by: Maxwell, January 6, 1983 11:06 am Last Edited by: Plass, April 15, 1983 1:10 pm Make viewer's load history point to current contents of parent Cannot do the destroy until after have released lock. Cannot have document or tdd locked when call this or may deadlock. need to deselect before make new viewer copy height and position info from old to new make parent iconic without doing paints in the column, just paint the icon Cannot have document or tdd locked when call this or may deadlock. Create it iconic and then open to minimize time that have a bad viewer tree. -- this needs to work ok in case parent=NIL Ê'˜JšÏcJ™JJš3™3J™1J™-šÏk ˜ Jšžœžœ3˜=Jšœžœ&˜1Jšœžœ˜+Jšœ žœ=˜LJšœžœ ˜Jšœžœžœ˜J˜—šŸ œžœžœž˜1J˜šžœžœž˜%Jšœžœ˜J˜,Jšž˜—šžœžœ&žœž˜DJšžœžœ˜(Jšžœ˜—Jšœžœ˜Jšžœ˜J˜—J˜˜!J˜—šŸœžœžœžœ7˜]Jšžœžœžœ˜J˜%J˜—šŸœžœžœ7˜ZJ˜'Jšžœžœ˜IJ˜J˜—šŸ œžœžœžœ#˜BJšžœžœžœ˜Jšœ'žœ˜;J˜Jšžœžœžœžœ˜J˜Jšžœ"žœžœ˜0šžœžœžœ˜8J˜'Jšžœ˜ —Jšœžœ ˜!J˜—šŸœžœžœžœ˜8Jšžœ#˜*Jšžœžœžœ˜Jšžœ˜#J˜—šŸœžœžœ˜5Jšžœ#˜*Jš žœžœžœžœžœ˜ Jšžœžœžœ˜,J˜Jšžœžœ%˜@J˜—š Ÿœžœ žœžœžœž˜QJšœžœ žœ žœ˜/Jšœ žœ˜ Jšžœ ˜Jšžœ žœžœ%˜Kšžœ žœžœ˜OJ˜7—Jšžœ˜J˜—š Ÿœžœ žœžœžœžœ˜ZJšœžœ˜ Jš žœžœžœžœžœ˜,˜(Jšœžœ'žœžœ˜@—J˜—šœ žœ0˜TJšœžœ˜ Jšœžœ&˜9Jšžœžœžœ˜?Jšžœžœžœ˜(Jšœ-˜-šœ;˜;Jš œžœžœžœžœ˜K—J˜—J˜šŸ œžœžœ7žœ˜TJ˜—š Ÿ œžœžœ/žœžœž˜ZJšœ žœ˜J˜Jšžœ žœžœ/˜CJšžœžœžœ˜?Jšžœžœžœ˜(Jšœ-˜-šžœ/žœžœ˜Mšœ˜JšœOžœ˜U—J˜Jšžœ˜ —Jšœžœ˜Jšžœžœžœžœ˜J˜%Jšžœžœžœ˜2Jšžœžœžœ ˜XJ˜%Jšœ-žœ˜OJ˜ J˜šžœžœ˜0Jšœ˜J˜J˜&Jšœ5˜5Jšœ žœ!˜1Jšœžœ˜šžœ>ž˜DJšžœžœ˜8—Jšœ˜—Jšžœ˜J˜—šŸœžœ$žœ˜LJšžœžœžœžœ#˜NJšžœžœžœžœ%˜PJšžœžœžœžœ&˜QJ˜—šŸ œžœžœ"ž˜?šžœ žœž˜˜)Jšœ/˜/šœžœžœ&˜5Jšœžœ ˜J˜%J˜J˜Jšœžœ-˜IJšžœ žœžœ˜+š žœžœžœžœžœž˜OJšœ,˜,—Jšžœ˜#Jšœ(žœ˜,Jšœ%žœ˜+Jšœ žœ!˜2Jšœžœ˜J˜ J˜Jšœ/˜FJ˜#J˜—Jšœ"˜"J˜—Jšžœ˜—Jšžœ˜J˜—šŸœžœ˜Jšœ1žœ˜7J˜J˜—š Ÿ œžœžœžœžœ˜Dšžœžœžœž˜-Jšœžœ ˜*šžœžœžœ˜@Jšœ*žœ˜0Jšœžœžœ˜(—Jšžœ˜—Jšžœžœ˜J˜—šŸ œžœžœ˜0Jšœ$žœ˜*J˜$J˜Jšžœ˜J˜—š Ÿ œžœžœžœ žœžœ˜VJšœ žœ˜Jšœ˜Jšœ"žœžœžœ˜TJ˜—šŸœžœ˜Jšœ žœ+˜9Jšžœžœ˜%Jšœ žœ˜Jšœžœ˜Jšœžœžœ˜*Jšœ@žœ˜FJšœ$žœ˜)Jšžœ žœžœ˜šžœ!žœ˜@š žœžœžœžœ+žœžœž˜UJšœ/˜/Jšžœ žœžœ˜Jšžœ˜—Jšœžœ˜ Jšœ ˜ Jšœ žœ˜—šžœ˜Jšœ!˜;Jšœ"˜;Jšœ˜š žœžœžœžœ+žœžœž˜Ušžœžœ!žœž˜QJšœ žœžœ)˜D—Jšžœ˜—Jšœ˜—šžœžœžœ˜Jšœ žœ˜Jšœ5˜5Jšžœžœžœžœ˜)—šžœ žœžœ+˜Hš žœžœžœžœ+žœžœž˜UJšœ0˜0Jšžœ žœžœ˜Jšžœ˜——Jšœžœ˜J˜—šœžœžœ˜4Jšžœžœžœžœ˜7J˜—š Ÿœžœžœžœžœ˜OJšžœžœžœ˜LJ˜—š Ÿœžœ žœžœžœ˜UJšœžœ˜Jšœžœ˜ Jšœ žœ˜Jšžœ!žœžœ˜HJšžœK˜Ošžœžœ˜JšœNžœ˜TJšœ7˜7—Jšžœžœžœ&˜6JšœAžœ˜Gš žœžœžœžœ)žœžœž˜SJšœ0˜0Jšžœ žœžœ˜Jšžœ˜—Jšžœžœ˜J˜—šŸœžœžœ˜JJšœ'žœ ˜6J˜Jš žœžœžœžœžœ ˜?šžœEžœ˜MJ˜%Jšœ$˜?—šœ˜Jšœžœžœžœ˜K—J˜J˜—šŸœžœžœ˜7Jšœžœžœ.˜OJšœžœžœ,˜MJšžœžœžœžœ˜šžœžœžœ˜Jšœžœ˜*J˜/—J˜ J˜J˜—šŸœžœ˜/Jšœžœžœ0˜RJšžœžœžœžœ˜J˜-J˜J˜—šŸœžœžœ˜9Jšœ'žœ˜;Jšœžœžœ0˜RJ˜Jšžœžœžœžœ˜šžœžœžœ˜Jšœžœ˜+J˜4—J˜1J˜!J˜ Jšžœžœžœ˜J˜'J˜—šŸ œžœ)˜J˜Jšžœ˜—J˜—J˜%Jšžœžœ&žœžœ˜YJ˜J˜—šœ žœžœ˜Jšœ žœ˜J˜J˜—šŸœžœžœ˜3Jšœžœžœ*˜GJšœžœžœ(˜EJšžœžœžœžœ˜šžœžœžœ˜Jšœžœ˜&J˜+—J˜ J˜J˜—šŸœžœžœ"ž˜DJšœžœžœ˜)Jšžœ˜J˜—šŸœžœžœ"ž˜DJšœžœžœ˜(Jšžœ˜J˜—šŸœžœžœ"ž˜LJšœžœžœ˜'Jšžœ˜J˜—šœžœ˜*Jšœžœ ˜.J˜Jšœžœ ˜Jšœžœ˜Jšœžœ˜Jšžœžœžœžœ˜Jšœ*'˜QJšœžœ,˜9Jšœ ˜ š žœžœžœ$žœžœ˜AJšœHžœ˜NJ˜Jšžœ˜ —J˜Jšžœžœžœ˜(šœ!žœ ˜/JšœW˜W—J˜J˜—šŸœžœ-žœž˜RJ˜Jšœžœ ˜Jšœžœ˜J˜Jšœžœ˜Jšžœžœžœžœ˜Jšœ-'˜TJšœžœ,˜9Jšœ ˜ š žœžœžœ$žœžœ˜AJšœHžœ˜NJ˜Jšžœ˜ —J˜-Jšžœžœžœ˜(Jšžœžœžœ)˜@Jšžœ1˜5Jšžœ˜J˜—šŸœžœ*žœ˜CJšžœžœ˜šžœžœ˜Jšœ*žœ˜0J˜Jšžœžœ˜—Jšžœžœžœžœ˜*Jšžœžœ˜J˜J˜—šŸ œžœ žœžœ˜Fšžœ%žœ˜-Jšœ0žœ˜6J˜Jšžœžœ˜—Jšžœžœ˜J˜J˜—šŸœžœžœ˜ JšœIžœ˜QJšœ žœ˜Jšžœžœžœ˜$Jšœ&˜&Jšœ&˜&Jšžœžœžœ˜,Jšœ žœ˜;J˜J˜—šŸ œžœ˜Jšœ(žœ˜-Jšœžœžœ-žœ˜DJšžœ#˜*Jšœžœ˜Jšžœžœžœ˜;Jšœ?˜?Jšžœ*žœžœ˜NJ˜J˜—šŸœžœžœ#˜EJšœ žœ˜Jšžœžœžœ˜$Jšœ&˜&Jšœ&˜&Jšžœžœžœ˜,J˜$J˜J˜—š Ÿœžœ*žœ žœžœ˜[Jšžœ˜Jšœžœ˜J˜/Jšžœ*žœžœ˜NJ˜J˜—šŸœžœžœ#˜8Jšœžœžœ˜&J˜—šŸ œžœžœ˜Jšœ(žœžœ žœž˜HJšœ+žœ˜/Jšžœ"ž˜.J˜Jšžœ žœžœ/˜CJšœžœ˜Jšžœžœžœžœ˜Jšœ2˜NJšžœ!žœžœ˜/JšœD˜DJšžœ˜J˜—šŸ œžœžœ#˜J˜—šŸœžœ˜1J™>Jšœžœ(˜1Jšœ#˜#J˜—šŸœžœ˜*Jšœžœ(˜1Jšœ#˜#J˜—š Ÿœžœžœ žœžœ˜_Jšžœ ž˜Jšœžœžœ˜J˜%Jšœ!˜!J˜(Jšœžœžœ˜Jšœžœ˜J˜-Jšžœžœžœžœ˜8šžœ'žœ˜/JšœFžœ˜LJšžœ ˜—Jšœ<žœ˜BJšœ˜Jšœžœ˜Jšžœžœžœžœ ˜"Jšœ ˜ Jšžœžœžœ˜2šžœ žœžœ˜šžœžœ˜J˜ Jšœ$˜$Jšžœžœ ˜;—Jšœ.˜Dš žœžœžœžœž˜JJšœ,˜,—Jšžœ ˜$—Jšžœ˜Jšœžœ˜ Jšœ œ.˜>J˜*Jšœ%žœ˜+šžœ žœžœžœžœ žœžœžœ ˜nJ˜)J˜#Jšœ#˜#J˜J˜J˜J˜?J˜J˜$J˜šžœžœžœ˜J˜J˜+—šžœžœ$žœž˜EJšžœžœ˜#Jšžœ˜—JšœGžœ˜MJšœžœ˜šžœžœž˜;Jšžœ žœžœ˜IJšž˜—Jšœ˜—šžœ˜Jšœ8˜8Jšœ žœ0˜@šžœžœžœ˜šœ˜JšœDžœ˜J—J˜Jšœžœ˜—Jšœ˜Jšœžœ˜Jšœžœ˜—J˜šžœ@ž˜FJšžœžœžœžœ˜N—J˜ šžœžœžœ(˜CJ™5—Jšžœžœ˜+Jšžœ ˜Jšžœ˜J˜—šŸœžœ#˜9JšœE˜EJ˜—šŸœžœ žœ˜TJ™B˜Jšœ'™'—Jšœžœ˜&J™-Jšœ&˜&Jšœ"˜"Jšœ˜JšœJ™JJšœ-žœ˜4Jšœ$˜5J˜J˜—šŸ œžœ'žœžœ˜FJšžœ˜J™B˜FJš œžœžœžœžœžœ žœ˜Q—šžœ!žœ˜)Jšœ'žœ˜;Jšžœžœžœ˜&—šœ(žœ˜/J™L—šžœ žœžœ#˜:JšœBžœ˜IJšœ'žœ˜.J˜VJ˜—Jšžœ˜Jšžœžœ)˜JJ˜J˜—JšŸœžœžœ9˜WJ˜šŸœžœžœ˜?Jšžœ ˜'Jšœ7˜7šœžœžœ&˜5J˜!J˜ J˜—Jšœ"˜"J˜J˜—šŸ œžœžœ?˜UJ˜—šŸ œžœžœ!žœ˜=Jšžœž˜+Jšœ7˜7šœžœžœ&˜5Jšœ-žœ˜6—Jšœ"˜"Jšžœ˜J˜—šŸœžœžœ/žœ˜TJšœžœžœ˜9J˜—š Ÿœžœžœžœžœ˜FJšžœžœžœ˜KJ˜—šŸœžœžœ#˜8Jšœžœ ˜J˜—šŸ œžœžœ˜Jšœ žœžœ5žœ˜MJšžœ"ž˜.Jšœžœ˜Jšžœ žœžœ/˜CJšžœžœžœ˜'Jšžœžœžœ˜;JšœD˜DJšžœ"žœžœ˜FJšžœ˜J˜—šŸœžœžœ:žœ˜bJ˜—š Ÿœžœžœžœžœ˜JJšžœžœ#žœ˜OJ˜—šŸ œžœžœ"ž˜@Jšœžœ ˜!Jšžœ˜J˜—š Ÿœžœžœ žœžœ!žœ˜VJšžœž˜ Jšœžœ˜Jšžœ žœžœ/˜CJšžœžœžœ˜'J˜4Jšžœ"žœžœ˜FJšžœ˜J˜—š Ÿ œžœ žœžœžœ˜9Jšžœžœžœžœ˜AJšžœžœžœžœ˜*Jšžœžœ˜J˜—šŸœžœ žœ-˜JJšžœž˜ Jš+™+Jšœžœžœ˜Jšœžœ˜J˜-Jšžœžœžœžœ˜9Jšœ%žœžœ˜FJšžœ˜J˜—š Ÿ œž œžœžœž˜GJ˜Jšœžœ˜šŸœžœ,˜8šœžœž˜*Jšœ)žœžœ˜8—Jšžœ žœžœžœ˜J˜ J˜—J˜SJ˜VJšžœžœ$˜1Jšžœ˜J˜—JšœY˜YJšœa˜aJšœ`˜`J˜Jšžœ˜J˜J˜—…—nVw