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], TiogaNode USING [Location, nullLocation, Offset, Ref, RefTextNode], TiogaNodeOps USING [LocNumber, LocWithin, NarrowToTextNode, Root], TiogaDisplay USING [EstablishLine], TiogaDocument USING [LineTableRec, maxClip, Selection, SpinAndLock, TiogaDocumentData, Unlock], TiogaDocumentPrivate, TiogaInput USING [FreeTree], TiogaInputOps USING [WaitForInsertToFinish], TiogaOps, TiogaProfile USING [DefaultMenuChoice, menu1, menu2, menu3, openFirstLevelOnly, sourceExtensions, implExtensions], TiogaSelection 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]; TiogaDocuments2Impl: CEDAR MONITOR IMPORTS CIFS, Menus, MessageWindow, NodeProps, Process, Rope, RopeEdit, RTMiniModel, TiogaDocument, TiogaDocumentPrivate, TextEdit, TiogaNodeOps, TiogaDisplay, TiogaInput, TiogaInputOps, TiogaProfile, TiogaSelection, ViewerOps, ViewerTools, VirtualDesktops EXPORTS TiogaDocument, TiogaDocumentPrivate, TiogaOps SHARES ViewerClasses = BEGIN OPEN Rope, TiogaDocument, TiogaDocumentPrivate, ViewerClasses; 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: TiogaNode.Ref; lastViewer: ViewerClasses.Viewer; RecordViewerForRoot: PUBLIC ENTRY PROC [viewer: ViewerClasses.Viewer, root: TiogaNode.Ref] = { ENABLE UNWIND => NULL; RecordViewerForRootI[viewer, root] }; RecordViewerForRootI: INTERNAL PROC [viewer: ViewerClasses.Viewer, root: TiogaNode.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: TiogaDocument.TiogaDocumentData = NARROW[viewer.data]; root: TiogaNode.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: TiogaNode.Ref] RETURNS [viewer: ViewerClasses.Viewer] = { ENABLE UNWIND => NULL; RETURN [GetViewerForRootI[root]] }; GetViewerForRootI: INTERNAL PROC [root: TiogaNode.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: TiogaDocumentData; 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: TiogaNode.Offset; KillSelections[parent]; [] _ SpinAndLock[tdd, "DoStoreFile2"]; loc _ TiogaNodeOps.LocNumber[tdd.lineTable.lines[0].pos]; tdd.text _ NIL; -- so InitViewerDoc won't free it InitViewerDoc[parent, NIL]; IF ~PositionViewer[parent,TiogaNodeOps.LocWithin[tdd.text,loc],all] THEN TRUSTED {Process.Detach[FORK PaintAndRemember[parent]]}; Unlock[tdd] }; END; KillSelections: PROC [parent: ViewerClasses.Viewer] = { OPEN TiogaSelection; 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: TiogaDocument.TiogaDocumentData => { TiogaSelection.LockSel[primary, "EmptyViewer"]; { ENABLE UNWIND => TiogaSelection.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 TiogaInput.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] }; TiogaSelection.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.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 { TRUSTED { Process.Detach[FORK IllegalFileName[]] }; 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 _ TiogaProfile.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 _ TiogaProfile.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 _ TiogaProfile.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 _ TiogaProfile.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: TiogaDocument.TiogaDocumentData _ NARROW[v.data]; loc: TiogaNode.Location; IF tdd = NIL OR Rope.Size[search] = 0 THEN RETURN; -- forget it IF (loc _ TiogaNodeOps.LocWithin[tdd.text,0]) # tdd.lineTable.lines[0].pos THEN { TiogaDisplay.EstablishLine[tdd, loc]; ViewerOps.PaintViewer[v, client] }; -- always search from start TiogaSelection.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 _ 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 _ TiogaNode.nullLocation; }; RememberCurrentPosition: PUBLIC PROC [viewer: Viewer] = { tdd: TiogaDocument.TiogaDocumentData _ NARROW[viewer.data]; prop: REF PositionHistory _ NARROW[ViewerOps.FetchProp[viewer, $PositionHistory]]; loc: TiogaNode.Location; IF tdd=NIL THEN RETURN; IF prop = NIL THEN { prop _ 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: TiogaNode.Location] RETURNS [good: BOOLEAN, goodloc: TiogaNode.Location] = { root, node: TiogaNode.Ref; t1: TiogaNode.RefTextNode; tdd: TiogaDocument.TiogaDocumentData; 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 TiogaNodeOps.Root[node] # root THEN GOTO Failed; -- make sure still in the tree IF (t1 _ TiogaNodeOps.NarrowToTextNode[node])=NIL OR loc.where NOT IN [0..TextEdit.Size[t1]] THEN RETURN [TRUE, [node,0]]; RETURN [TRUE,loc]; EXITS Failed => RETURN [FALSE, TiogaNode.nullLocation]; }; PositionViewer: PUBLIC PROC [ viewer: Viewer, loc: TiogaNode.Location, hint: ViewerOps.PaintHint _ client] RETURNS [ok: BOOLEAN] = { tdd: TiogaDocument.TiogaDocumentData _ NARROW[viewer.data]; node: TiogaNode.RefTextNode; [ok, loc] _ CheckPosition[viewer, loc]; IF tdd = NIL OR ~ok THEN RETURN; RememberCurrentPosition[viewer]; IF (node _ TiogaNodeOps.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 }; TiogaDisplay.EstablishLine[tdd, loc]; TRUSTED {Process.Detach[FORK ViewerOps.PaintViewer[viewer, hint ! ABORTED => CONTINUE]]}; }; LoadHistory: TYPE = RECORD [ name: Rope.ROPE, place: TiogaNode.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 _ 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: TiogaDocumentData; 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: TiogaDocumentData; prop: REF LoadHistory; propName: Rope.ROPE; propPlace: TiogaNode.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]; }; 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.ROPE; IF ~CheckNoFile[parent] THEN RETURN; TiogaInputOps.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 ~CheckNoFile[parent] THEN RETURN; TiogaInputOps.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: TiogaDocumentData; 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: TiogaDocumentData; 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 _ NEW[LoadHistory]; ViewerOps.AddProp[viewer, $LoadHistory, prop] }; SetLoadHistoryInfo: PROC [viewer: Viewer, prop: REF LoadHistory] = { tdd: TiogaDocument.TiogaDocumentData _ NARROW[viewer.data]; IF tdd = NIL THEN RETURN; prop.name _ viewer.file; prop.place _ TiogaNodeOps.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: TiogaNode.Offset _ 0] RETURNS [Viewer] = BEGIN new: BOOLEAN _ FALSE; tdd: TiogaDocument.TiogaDocumentData; oldViewer, destroyViewer: Viewer; tddOld: TiogaDocument.TiogaDocumentData; 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 TiogaInput.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 _ [TiogaNodeOps.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[directoryName]] }; 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: TiogaNode.Ref _ FindUnsavedDocument[directoryName]; tdd.text _ NIL; -- so InitViewerDoc won't worry about freeing it IF root # NIL THEN { TRUSTED {Process.Detach[FORK ReloadedMessage[directoryName]] }; -- can deadlock if don't fork clearMessage _ FALSE }; InitViewerDoc[viewer, root]; viewer.newVersion _ root # NIL; viewer.newFile _ FALSE }; ClearPositionHistory[viewer]; IF ~PositionViewer[viewer,TiogaNodeOps.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.ROPE] = { MessageWindow.Append[Rope.Concat[name," was already loaded."],TRUE] }; ReloadedMessage: PROC [name: Rope.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 TiogaProfile.openFirstLevelOnly THEN { tdd: TiogaDocument.TiogaDocumentData _ 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] = { TiogaSelection.LockSel[primary, "DoCloseAndNewViewer"]; { ENABLE UNWIND => TiogaSelection.UnlockSel[primary]; new _ ReplaceByNewViewer[parent]; ViewerOps.PaintViewer[new, all]; ForceInitialCaret[new] }; TiogaSelection.UnlockSel[primary]; }; NewViewer: PUBLIC PROC [parent: ViewerClasses.Viewer] = { [] _ DoNewViewer[parent] }; DoNewViewer: PUBLIC PROC [parent: ViewerClasses.Viewer _ NIL] RETURNS [new: ViewerClasses.Viewer] = BEGIN TiogaSelection.LockSel[primary, "DoCloseAndNewViewer"]; { ENABLE UNWIND => TiogaSelection.UnlockSel[primary]; ForceInitialCaret[new _ MakeNewViewer[parent,TRUE]] }; TiogaSelection.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: TiogaNode.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: TiogaProfile.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[TiogaProfile.menu1]; DoLine[TiogaProfile.menu2]; DoLine[TiogaProfile.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. ö-- TiogaDocuments2Impl.mesa; Edited by Paxton on June 7, 1983 9:38 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šÏcE™EJš3™3J™1J™-šÏk ˜ Jšžœžœ3˜=Jšœžœ&˜1Jšœžœ˜+Jšœ žœ=˜LJšœžœ ˜Jšœžœžœ˜J˜—šŸ œžœžœž˜1J˜šžœžœž˜%Jšœžœ˜J˜,Jšž˜—šžœžœ&žœž˜DJšžœžœ˜(Jšžœ˜—Jšœžœ˜Jšžœ˜J˜—J˜˜!J˜—šŸœžœžœž˜&Jšœ7˜7Jšžœžœžœ˜J˜%J˜—šŸœžœžœ8˜[J˜'Jšžœžœ˜IJ˜J˜—šŸ œžœžœžœ#˜BJšžœžœžœ˜Jšœ'žœ˜;J˜Jšžœžœžœžœ˜J˜Jšžœ"žœžœ˜0šžœžœžœ˜8J˜'Jšžœ˜ —Jšœžœ ˜!J˜—šŸœžœžœžœ˜9Jšžœ#˜*Jšžœžœžœ˜Jšžœ˜#J˜—šŸœžœžœ˜6Jšžœ#˜*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šœ9˜9Jšœ žœ!˜1Jšœžœ˜šžœBž˜HJšžœžœ˜8—Jšœ˜—Jšžœ˜J˜—šŸœžœ$žœ˜LJšžœžœžœžœ#˜NJšžœžœžœžœ%˜PJšžœžœžœžœ&˜QJ˜—šŸ œžœžœ"ž˜?šžœžœžœ žœžœžœ žœž˜C˜)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˜—šŸœžœ˜Jšœ+žœ˜1J˜J˜—š Ÿ œžœžœžœžœ˜Dšžœžœžœž˜-Jšœžœ ˜*šžœžœžœ˜@Jšžœžœ˜3Jšžœžœ˜—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š žœžœžœžœžœ ˜?šžœIžœ˜QJ˜%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šžœžœ"˜8J˜J˜Jšœ%˜%Jšžœžœžœžœžœžœžœ˜LJš žœžœžœžœžœ˜6Jšžœžœžœžœ˜*Jšžœ žœžœ ˜Ršžœ,žœž˜4Jš œ žœžœžœžœžœ ˜E—Jšžœžœ˜Jšžœ žœžœ˜7J˜J˜—šŸœžœžœ˜JšœM˜MJšžœžœ˜Jšœ'žœ˜;J˜J˜'Jš žœžœžœžœžœ˜ J˜ šžœ4žœžœ˜XJšœžœžœžœ$˜;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šœ7žœ˜=J˜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˜—šŸœžœ˜*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˜CJ˜J˜$J˜šžœžœžœ˜J˜J˜+—šžœžœ$žœž˜EJšžœžœ˜#Jšžœ˜—Jšžœžœ$˜@Jšœžœ˜šžœžœž˜;Jšžœ žœžœ˜IJšž˜—Jšœ˜—šžœ˜Jšœ9˜9Jšœ žœ0˜@šžœžœžœ˜Jšžœžœ$˜]Jšœžœ˜—Jšœ˜Jšœžœ˜Jšœžœ˜—J˜šžœDž˜JJšžœžœžœžœ˜N—J˜ šžœžœžœ(˜CJ™5—Jšžœžœ˜+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šžœ"ž˜.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˜—šŸœžœ žœ.˜KJšžœž˜ 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˜—…—o²’p