DIRECTORY AMMiniModel USING [ImplementorName], FS USING [ComponentPositions, Error, ExpandName, FileInfo, GetName, nullOpenFile, Open, OpenFile], 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, Flatten, ROPE, Size, SkipTo, Substr], RopeEdit USING [BlankChar, IllegalChar], 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, TEditDocumentPrivateExtras USING [InitViewerDocInternal], 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], WorldVM USING [LocalWorld, World]; TEditDocuments2Impl: CEDAR MONITOR IMPORTS AMMiniModel, FS, Menus, MessageWindow, NodeProps, Process, Rope, RopeEdit, TEditDocument, TEditDocumentPrivate, TEditDocumentPrivateExtras, TextEdit, TextNode, TEditDisplay, TEditInput, TEditInputOps, TEditProfile, TEditSelection, ViewerOps, ViewerTools, VirtualDesktops, WorldVM EXPORTS TEditDocument, TEditDocumentPrivate, TEditOps SHARES ViewerClasses = BEGIN OPEN Rope, TEditDocument, TEditDocumentPrivate, ViewerClasses; ROPE: TYPE = Rope.ROPE; ForceInitialCaret: PROC [viewer: Viewer] = {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]]] }; GetFileName: PROC[file: FS.OpenFile, removeVersion: BOOL _ FALSE] RETURNS[name: ROPE _ NIL] = { name _ FS.GetName[file ! FS.Error => CONTINUE].fullFName; IF name#NIL AND removeVersion THEN name _ name.Flatten[0, name.SkipTo[0, "!"]]; }; GetCreateName: PROC[name: ROPE] RETURNS[ROPE] = { cp: FS.ComponentPositions; [fullFName: name, cp: cp] _ FS.ExpandName[name ! FS.Error => GOTO Fail]; RETURN[name.Flatten[start: cp.subDirs.start, len: cp.ext.start+cp.ext.length-cp.subDirs.start]]; EXITS Fail => { TRUSTED { Process.Detach[FORK IllegalFileName[]] }; RETURN[NIL]; }; }; IsNewFile: PROC[name: ROPE] RETURNS[new: BOOL _ FALSE] = { [] _ FS.FileInfo[name ! FS.Error => { new _ TRUE; CONTINUE }]; }; PreStore: PUBLIC Menus.MenuProc = { -- called when Store menu item becomes unguarded sel: ROPE _ ViewerTools.GetSelectionContents[]; fileName: ROPE _ NIL; new: BOOL _ FALSE; IF Rope.Size[sel]=0 THEN {PleaseSelectFileName[]; RETURN}; fileName _ GetCreateName[sel]; IF fileName=NIL THEN RETURN; new _ IsNewFile[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 _ NIL] = BEGIN linked: BOOL; tdd: TEditDocumentData; IF fileName=NIL THEN fileName _ ViewerTools.GetSelectionContents[]; IF Rope.Size[fileName]=0 THEN {PleaseSelectFileName[]; RETURN}; fileName _ GetCreateName[fileName]; IF fileName=NIL THEN 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 IF parent#NIL AND parent.data#NIL THEN WITH parent.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { TEditSelection.LockSel[primary, "EmptyViewer"]; { ENABLE UNWIND => TEditSelection.UnlockSel[primary]; prop: REF LoadHistoryEtc; [] _ SpinAndLock[tdd, "EmptyViewer"]; KillSelections[parent]; SaveLoadHistory[parent]; prop _ NARROW[ViewerOps.FetchProp[parent, $LoadHistoryEtc]]; -- 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, $LoadHistoryEtc, 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[] }; IllegalFileName: PROC = { MessageWindow.Append["Illegal file name.", TRUE]; MessageWindow.Blink[] }; CheckFileName: PROC [directoryName: ROPE] RETURNS [BOOLEAN] = { FOR i: INT IN [0..Rope.Size[directoryName]) DO char: CHAR _ Rope.Fetch[directoryName, i]; IF RopeEdit.BlankChar[char] OR RopeEdit.IllegalChar[char] THEN { TRUSTED { Process.Detach[FORK IllegalFileName[]] }; RETURN [FALSE] }; ENDLOOP; RETURN [TRUE] }; UnknownFile: PROC [directoryName: ROPE] = { MessageWindow.Append[directoryName, TRUE]; MessageWindow.Append[" not found."]; MessageWindow.Blink[]; RETURN}; TryToOpen: PROC[name: ROPE] RETURNS[file: FS.OpenFile] = { file _ FS.Open[name ! FS.Error => { file _ FS.nullOpenFile; CONTINUE }]; }; FileExists: PROC[file: FS.OpenFile] RETURNS[BOOL] = INLINE { RETURN[file#FS.nullOpenFile] }; TryExtensions: PROC[name: ROPE, extensions: LIST OF ROPE] RETURNS[FS.OpenFile] = { FOR lst: LIST OF ROPE _ extensions, lst.rest UNTIL lst=NIL DO file: FS.OpenFile ~ TryToOpen[name.Concat[lst.first]]; IF FileExists[file] THEN RETURN[file]; ENDLOOP; RETURN[FS.nullOpenFile]; }; IsAnExtension: PROC[ext: ROPE, extensions: LIST OF ROPE] RETURNS[BOOL] = { FOR lst: LIST OF ROPE _ extensions, lst.rest UNTIL lst=NIL DO IF Rope.Equal[ext, lst.first, FALSE] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; fileNameProc: PROC [ROPE, ViewerClasses.Viewer] RETURNS [fileName: ROPE, search: ROPE] _ NIL; RegisterFileNameProc: PUBLIC PROC [proc: PROC [ROPE, ViewerClasses.Viewer] RETURNS [fileName: ROPE, search: ROPE]] = { fileNameProc _ proc }; TryFileNameProc: PROC[sel: ROPE, viewer: ViewerClasses.Viewer] RETURNS[file: FS.OpenFile _ FS.nullOpenFile, search: ROPE] = { name, srch: ROPE _ NIL; IF fileNameProc#NIL THEN [name, srch] _ fileNameProc[sel, viewer]; IF name#NIL THEN { file _ TryToOpen[name]; IF FileExists[file] THEN RETURN[file, srch]; }; RETURN[FS.nullOpenFile, NIL]; }; HasVersion: PROC[name: ROPE] RETURNS[BOOL] = { RETURN[name.Find["!"]>=0]; }; LookupProc: TYPE = PROC[sel: ROPE, fileNameProcViewer: Viewer _ NIL] RETURNS[name: ROPE _ NIL, file: FS.OpenFile, search: ROPE _ NIL]; LookupFile: LookupProc = { MessageWindow.Append[Rope.Concat["Directory lookup for ", sel], TRUE]; file _ TryToOpen[sel]; IF HasVersion[sel] THEN { -- explicit version number IF FileExists[file] THEN name _ GetFileName[file: file, removeVersion: FALSE]; RETURN; -- give up if the file was not found }; IF NOT FileExists[file] THEN { dot: INT ~ sel.Find["."]; -- find the first dot, if any, in the selection extensions: LIST OF ROPE ~ TEditProfile.sourceExtensions; IF dot<0 THEN { file _ TryExtensions[sel, extensions]; IF NOT FileExists[file] THEN [file, search] _ TryFileNameProc[sel, fileNameProcViewer]; } ELSE { [file, search] _ TryFileNameProc[sel, fileNameProcViewer]; IF NOT FileExists[file] AND NOT IsAnExtension[sel.Substr[dot], extensions] THEN { base: ROPE ~ sel.Substr[0, dot]; -- the text before the "." search _ sel.Substr[dot+1]; -- the text after the "." file _ TryExtensions[base, extensions]; }; }; }; IF FileExists[file] THEN name _ GetFileName[file: file, removeVersion: TRUE]; }; LookupImpl: LookupProc = { defs, impl: ROPE _ NIL; dot: INT ~ sel.Find["."]; -- find the first dot, if any IF dot<0 THEN { defs _ sel; search _ NIL } -- no dot ELSE { defs _ sel.Substr[0, dot]; search _ sel.Substr[dot+1] }; IF search.Size>0 THEN { world: WorldVM.World; MessageWindow.Append[Rope.Concat["Model lookup for implementor of ", search], TRUE]; TRUSTED { world _ WorldVM.LocalWorld[] }; impl _ AMMiniModel.ImplementorName[defs, search, world]; }; IF impl=NIL THEN impl _ defs.Concat["Impl"]; MessageWindow.Append[Rope.Concat["Directory lookup for ", impl], TRUE]; file _ TryExtensions[impl, TEditProfile.implExtensions]; IF FileExists[file] THEN name _ GetFileName[file: file, removeVersion: TRUE]; }; DoSearch: PROC [v: Viewer, search: 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]]}; }; LoadHistoryEtc: TYPE = RECORD [ name: ROPE, place: TextNode.Offset ]; CopyLoadHistory: PUBLIC PROC [from, to: Viewer] = { old: REF LoadHistoryEtc _ NARROW[ViewerOps.FetchProp[from, $LoadHistoryEtc]]; new: REF LoadHistoryEtc _ NARROW[ViewerOps.FetchProp[to, $LoadHistoryEtc]]; IF old=NIL THEN RETURN; IF new=NIL THEN { new _ TextNode.pZone.NEW[LoadHistoryEtc]; ViewerOps.AddProp[to, $LoadHistoryEtc, 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 LoadHistoryEtc; propName: ROPE; tdd _ NARROW[viewer.data]; IF tdd = NIL THEN RETURN; [] _ SpinAndLock[tdd, "PreLoadPrevious"]; -- delay until after other op completes prop _ NARROW[ViewerOps.FetchProp[viewer, $LoadHistoryEtc]]; 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 LoadHistoryEtc; propName: ROPE; propPlace: TextNode.Offset; file: FS.OpenFile; tdd _ NARROW[parent.data]; IF tdd = NIL THEN RETURN; [] _ SpinAndLock[tdd, "DoLoadPreviousFile"]; -- delay until after other op completes prop _ NARROW[ViewerOps.FetchProp[parent, $LoadHistoryEtc]]; 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; file _ TryToOpen[propName]; IF FileExists[file] THEN { IF open AND ~close THEN [] _ DoOpen[name: propName, file: file, parent: parent, place: propPlace] ELSE [] _ DoLoad[viewer: parent, name: propName, file: file, close: close, place: propPlace]; } ELSE UnknownFile[propName]; END; CheckAnonymous: PROC [parent: ViewerClasses.Viewer, txt: 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]; }; CheckNoFile: PROC [parent: ViewerClasses.Viewer] RETURNS [BOOLEAN] = { IF parent.file # NIL THEN { MessageWindow.Append["Viewer already contains a file.",TRUE]; MessageWindow.Blink[]; RETURN [FALSE]}; RETURN [TRUE]; }; AnonymousLoadFile: PUBLIC PROC [ parent: ViewerClasses.Viewer, fileNameProcViewer: ViewerClasses.Viewer _ NIL] = { txt: ROPE; IF ~CheckNoFile[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, close: BOOL _ FALSE, fileNameProcViewer: ViewerClasses.Viewer _ NIL] RETURNS [viewer: ViewerClasses.Viewer] = { RETURN[DoLoadAndSearch[parent: parent, txt: txt, lookup: LookupFile, close: close, fileNameProcViewer: fileNameProcViewer]]; }; AnonymousLoadImplFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = { txt: ROPE; IF ~CheckNoFile[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, close: BOOL _ FALSE] RETURNS [viewer: Viewer] = { RETURN[DoLoadAndSearch[parent: parent, txt: txt, lookup: LookupImpl, close: close, fileNameProcViewer: NIL]]; }; 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] RETURNS [BOOLEAN] = { IF Rope.Size[sel]=0 THEN { PleaseSelectFileName[]; RETURN[FALSE]}; IF ~CheckFileName[sel] THEN RETURN[FALSE]; RETURN [TRUE] }; AllocLoadHistoryEtc: PROC [viewer: Viewer] RETURNS [prop: REF LoadHistoryEtc] = { IF (prop _ NARROW[ViewerOps.FetchProp[viewer, $LoadHistoryEtc]]) # NIL THEN RETURN; prop _ TextNode.pZone.NEW[LoadHistoryEtc]; ViewerOps.AddProp[viewer, $LoadHistoryEtc, prop] }; SetLoadHistoryInfo: PROC [viewer: Viewer, prop: REF LoadHistoryEtc] = { tdd: TEditDocument.TEditDocumentData _ NARROW[viewer.data]; IF tdd = NIL THEN RETURN; prop.name _ viewer.name; prop.place _ TextNode.LocNumber[tdd.lineTable.lines[0].pos]; }; SetLoadHistory: PROC [parent, viewer: Viewer] = { prop: REF LoadHistoryEtc _ AllocLoadHistoryEtc[viewer]; SetLoadHistoryInfo[parent, prop] }; SaveLoadHistory: PROC [viewer: Viewer] = { prop: REF LoadHistoryEtc _ AllocLoadHistoryEtc[viewer]; SetLoadHistoryInfo[viewer, prop] }; DoLoadAndSearch: PROC[parent: Viewer, txt: ROPE, lookup: LookupProc, close: BOOL _ FALSE, fileNameProcViewer: Viewer _ NIL] RETURNS[viewer: Viewer] = { name: ROPE; file: FS.OpenFile; search: ROPE; IF fileNameProcViewer=NIL THEN fileNameProcViewer _ parent; [name, file, search] _ lookup[txt, fileNameProcViewer]; IF FileExists[file] THEN { viewer _ DoLoad[viewer: parent, name: name, file: file, close: close]; IF viewer#NIL AND search#NIL THEN DoSearch[viewer, search]; } ELSE { UnknownFile[txt]; RETURN[NIL] }; }; DoLoad: PROC [viewer: Viewer, name: ROPE, file: FS.OpenFile, close: BOOL _ FALSE, place: TextNode.Offset _ 0] RETURNS [Viewer] = BEGIN tdd: TEditDocument.TEditDocumentData; oldViewer, destroyViewer: Viewer; tddOld: TEditDocument.TEditDocumentData; clearMessage: BOOL _ TRUE; fileName: ROPE _ GetFileName[file]; IF Rope.Equal[viewer.file, fileName, FALSE] THEN { MessageWindow.Append[Rope.Concat[fileName," is already loaded."],TRUE]; RETURN [viewer] }; MessageWindow.Append[Rope.Concat["Loading ", name],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, name, 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[name]; viewer.name _ name; viewer.file _ fileName; viewer.newVersion _ viewer.newFile _ FALSE; IF oldViewer # NIL AND NOT oldViewer.destroyed AND (tddOld _ NARROW[oldViewer.data]) # NIL THEN { -- link them viewer.name _ oldViewer.name; viewer.file _ oldViewer.file; 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; TRUSTED {Process.Detach[FORK WasLoadedMessage[name]] }; 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[name]; tdd.text _ NIL; -- so InitViewerDoc won't worry about freeing it IF root # NIL THEN { TRUSTED {Process.Detach[FORK ReloadedMessage[name]] }; -- can deadlock if don't fork clearMessage _ FALSE; }; TEditDocumentPrivateExtras.InitViewerDocInternal[viewer, file, root]; viewer.newFile _ FALSE; viewer.newVersion _ root#NIL; }; 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; WasLoadedMessage: PROC [name: ROPE] = { MessageWindow.Append[Rope.Concat[name," was already loaded."],TRUE] }; ReloadedMessage: PROC [name: ROPE] = { MessageWindow.Append[ Rope.Concat[name," restored with previous unsaved edits."],TRUE]; MessageWindow.Blink[] }; 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 RETURN[DoOpenAndSearch[txt: fileName, lookup: LookupFile, parent: parent, fileNameProcViewer: fileNameProcViewer]] 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 RETURN[DoOpenAndSearch[txt: fileName, lookup: LookupImpl, parent: parent]] END; PreOpenCheck: PROC [sel: ROPE] RETURNS [BOOLEAN] = { IF Rope.Size[sel]=0 THEN {PleaseSelectFileName[]; RETURN[FALSE]}; IF ~CheckFileName[sel] THEN RETURN[FALSE]; RETURN [TRUE] }; DoOpenAndSearch: PROC[txt: ROPE, lookup: LookupProc, parent: Viewer _ NIL, fileNameProcViewer: Viewer _ NIL] RETURNS[viewer: Viewer] = { name: ROPE; file: FS.OpenFile; search: ROPE; IF txt=NIL THEN txt _ ViewerTools.GetSelectionContents[]; IF ~PreOpenCheck[txt] THEN RETURN[NIL]; IF fileNameProcViewer=NIL THEN fileNameProcViewer _ parent; [name, file, search] _ lookup[txt, fileNameProcViewer]; IF FileExists[file] THEN { viewer _ DoOpen[name: name, file: file, parent: parent]; IF viewer#NIL AND search#NIL THEN DoSearch[viewer, search]; } ELSE { UnknownFile[txt]; RETURN[NIL] }; }; DoOpen: PROC [name: ROPE, file: FS.OpenFile, parent: Viewer, place: TextNode.Offset _ 0] RETURNS [viewer: Viewer] = BEGIN viewer _ DoLoad[viewer: MakeNewViewer[parent,TRUE], name: name, file: file, close: FALSE, place: 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 Paxton on June 7, 1983 9:38 am McGregor on September 10, 1982 1:53 pm Maxwell, January 6, 1983 11:06 am Plass, April 15, 1983 1:10 pm Russ Atkinson, September 26, 1983 3:20 pm L. Stewart, November 3, 1983 3:28 pm Doug Wyatt, December 15, 1983 6:42 pm Include subDirs, base, and extension (omit server, dir, and version) checkForInViewer: BOOL _ FALSE; IF checkForInViewer AND 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}; First, try the entire selection as the file name If there is no dot, try appending extensions to sel to get a full file name. If there is a dot, separate sel into "name" (before dot) and "ext" (dot and after) parts. If ext is not a standard extension, try appending extensions to name to get a full file name. Try the file name proc first (for example, the extension might be misspelled). 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 Ê"r˜šœ™Jšœ™Jšœ&™&J™!J™J™)J™$J™%J™—šÏk ˜ Jšœ œ˜$JšœœZ˜bJšœœ&˜1Jšœœ˜+Jšœ œ=˜LJšœœ ˜Jšœœ'œ˜MJšœ œ˜(Jšœ œ˜šœ œ˜Jšœs˜s—Jšœ œ˜#šœœ˜JšœJ˜J—J˜Jšœœ˜9Jšœ œ ˜Jšœœ˜,J˜ šœ œ˜Jšœ^˜^—JšœœA˜Ušœ œ˜Jšœ®˜®—Jšœœ0˜CJšœ œF˜WJšœœ˜#Jšœœ˜"J˜—Jšœ ˜"J˜Jšœœˆ˜ŸJšœ.˜5Jšœ˜J˜Jšœœ:˜DJ˜Jšœœœ˜J˜JšÏnœœE˜\J˜šœ#œ˜>J˜—šž œœœ˜1J˜šœœ˜%Jšœœ˜J˜,Jš˜—šœœ&œ˜DJšœœ˜(Jšœ˜—Jšœœ˜Jšœ˜J˜—J˜˜!J˜—šžœœœ˜&Jšœ6˜6Jšœœœ˜J˜%J˜—šžœœœ7˜ZJ˜'JšœœÏc˜IJ˜J˜—šž œœœœ#˜BJšœœœ˜Jšœ'œ˜;J˜Jšœœœœ˜J˜Jšœ"œœ˜0šœœœŸ˜8J˜'Jšœ˜ —Jšœœ ˜!J˜—šžœœœœ˜8Jšœ#˜*Jšœœœ˜Jšœ˜#J˜—šžœœœ˜5Jšœ#˜*Jš œœœœœ˜ Jšœœœ˜,J˜Jšœœ%˜@J˜—š ž œœœœœ˜AJšœœœ˜Jšœœœ œ ˜9Jšœœœœ-˜OJšœ˜J˜—š ž œœœœœ˜1Jšœœ˜Jšœœœ œ˜HšœZ˜`JšœE™E—šœ ˜Jšœœ˜3Jšœœ˜ J˜—J˜J˜—š ž œœœœœœ˜:Jš œœœœœ˜>Jšœ˜J˜—šžœœŸ0˜TJšœœ&˜/Jš œ œœœœ˜(Jšœœœ˜:J˜Jšœ œœœ˜J˜šœ;˜;Jš œœœœœ˜K—J˜—J˜šž œœœ7œ˜TJ˜—Jšœœœ™J˜š ž œœœ*œœ˜UJšœœ˜ J˜Jšœ œœ/˜CJšœœœ˜?J˜#Jšœ œœœ˜J™šœ™Jšœ.œœŸ™Jšœ™JšœOœ™U—J™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˜—šž œœœ"˜?šœœœ œœœ œ˜C˜)Jšœ/˜/šœœœ&˜5Jšœœ˜J˜%J˜J˜Jšœœ0Ÿ˜LJšœ œœ˜+š œœœœœ˜OJšœ,˜,—Jšœ˜#Jšœ(œ˜,Jšœ%œ˜+Jšœ œŸ!˜2Jšœœ˜J˜ J˜Jšœ2Ÿ˜IJ˜#J˜—Jšœ"˜"J˜—Jšœ˜—Jšœ˜J˜—šžœœ˜Jšœ1œ˜7J˜J˜—šžœœ˜Jšœ+œ˜1J˜J˜—š ž œœœœœ˜?šœœœ˜.Jšœœ ˜*šœœœ˜@Jšœœ˜3Jšœœ˜—Jšœ˜—Jšœœ˜J˜—šž œœœ˜+Jšœ$œ˜*J˜$J˜Jšœ˜J˜—š ž œœœœœ˜:Jš œœ œœœ˜HJšœ˜J˜—šž œœœ œœœœœ˜\J˜—šž œœœœœœœœ˜Rš œœœœœœ˜=Jšœœ.˜6Jšœœœ˜&Jšœ˜—Jšœœ˜J˜J˜—šž œœœœœœœœ˜Jš œœœœœœ˜=Jš œœœœœ˜7Jšœ˜—Jšœœ˜J˜J˜—šœœœ˜/Jšœ œ œœ˜-J˜—š žœœœœœ˜JJšœ œ œ˜BJ˜—šžœœœ˜>Jšœœ œœ˜>Jšœ œœ˜Jšœœœ*˜Bšœœœ˜Jšœ˜Jšœœœ ˜,J˜—Jšœœœ˜J˜J˜—š ž œœœœœ˜.Jšœ˜J˜J˜—š œ œœœœ˜DJš œœœœœœ˜AJ˜—šž œ˜J˜Jšœ@œ˜FJ˜Jšœ Ÿ%™0J˜J˜šœœŸ˜4Jšœœ/œ˜NJšœŸ$˜,J˜—J˜šœœœ˜JšœœŸ/˜IJšœ œœœ!˜9J™JšœL™Lšœœ˜Jšœ&˜&Jšœœœ;˜WJšœ˜—J™JšœY™YJšœ]™]šœ˜J™NJšœ:˜:š œœœœ,œ˜QJšœœŸ˜;JšœŸ˜5Jšœ'˜'J˜—Jšœ˜—J˜—Jšœœ/œ˜MJšœ˜J˜—šž œ˜Jšœ œœ˜JšœœŸ˜7JšœœœŸ ˜4Jšœ;˜?šœœ˜J˜JšœNœ˜TJšœ"˜)Jšœ8˜8Jšœ˜—Jšœœœ˜,JšœAœ˜GJšœ8˜8Jšœœ/œ˜MJšœ˜J˜—šžœœœŸ˜EJšœ'œ ˜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˜J˜—šžœœœ˜3Jšœœœ-˜MJšœœœ+˜KJšœœœœ˜šœœœ˜Jšœœ˜)J˜.—J˜ J˜J˜—šžœœœ"˜DJšœœœ˜)Jšœ˜J˜—šžœœœ"˜DJšœœœ˜(Jšœ˜J˜—šžœœœ"˜LJšœœœ˜'Jšœ˜J˜—šžœœ˜*Jšœœ ˜.J˜Jšœœ˜Jšœ œ˜Jšœœ˜Jšœœœœ˜Jšœ*Ÿ'˜QJšœœ/˜Jšœœ˜šœœ˜Jšœ*œ˜0J˜Jšœœ˜—Jšœœœœ˜*Jšœœ˜J˜J˜—šž œœ œœ˜Fšœœœ˜Jšœ7œ˜=J˜Jšœœ˜—Jšœœ˜J˜J˜—šžœœœ˜ JšœIœ˜QJšœœ˜ Jšœœœ˜$Jšœ&˜&Jšœ&˜&Jšœœœ˜,Jšœ œ˜;J˜J˜—šž œœ˜Jšœ#œ˜(Jšœœœ-œ˜DJšœ#˜*šœ>˜DJšœ7˜7—J˜J˜—šžœœœ#˜EJšœœ˜ Jšœœœ˜$Jšœ&˜&Jšœ&˜&Jšœœœ˜,J˜$J˜J˜—š žœœ%œ œœ˜VJšœ˜šœ>˜DJšœ"œ˜(—J˜J˜—šžœœœ#˜8Jšœœœ˜&J˜—šž œœœ˜Jšœ(œœ œ˜HJšœ+œ˜/Jšœ"˜.J˜Jšœ œœ/˜CJšœœ˜Jšœœœœ˜Jšœ2Ÿ˜NJšœ!œœ˜/JšœD˜DJšœ˜J˜—šž œœœ#˜Jšœœ.˜7Jšœ#˜#J˜—šžœœ˜*Jšœœ.˜7Jšœ#˜#J˜—J˜šžœœœ˜DJšœœœœ˜6Jšœ˜Jšœœœœ˜,Jšœœœ˜;Jšœ7˜7šœœ˜JšœF˜FJš œœœœœ˜;J˜—Jšœœœ˜'J˜J˜—šžœœœœ ˜œ˜FJ˜—šžœœœ˜&šœ˜Jšœ;œ˜A—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šœ"˜.šœC˜IJšœ(˜(—Jšœ˜J˜—šžœœœ:œ˜bJ˜—š žœœœœœ˜JJšœœ#œ˜OJ˜—šž œœœ"˜@Jšœœ ˜!Jšœ˜J˜—š žœœœ œœ!œ˜VJšœ˜ JšœD˜JJšœ˜J˜—š ž œœœœœ˜4Jšœœœœ˜AJšœœœœ˜*Jšœœ˜J˜—šžœœœ˜4Jšœœœ˜7Jšœ˜Jšœœœœ˜,Jšœœœ*˜9Jšœœœœ˜'Jšœœœ˜;Jšœ7˜7šœœ˜Jšœ8˜8Jš œœœœœ˜;J˜—Jšœœœ˜'J˜J˜—šžœœœœ˜