DIRECTORY AMMiniModel USING [ImplementorName], BasicTime USING [GMT, nullGMT, Period], Convert USING [Error, IntFromRope], FS USING [ComponentPositions, Error, ExpandName, FileInfo, GetDefaultWDir, GetName, nullOpenFile, Open, OpenFile], Menus USING [Menu, MenuEntry, MenuProc, SetLine], MessageWindow USING [Append, Blink, Clear], NodeProps USING [GetProp, NullCopy, NullRead, NullWrite, PutProp, Register], Rope USING [Concat, Equal, Fetch, Flatten, Find, Match, ROPE, Size, SkipTo, Substr], TEditDisplay USING [EstablishLine], TEditDocument USING [maxClip, Selection, SpinAndLock, TEditDocumentData, Unlock], TEditDocumentPrivate USING [findMenu, FindUnsavedDocument, InitViewerDoc, InitViewerDocInternal, levelMenu, PositionHistory, RecordUnsavedDocument], TEditInput USING [FreeTree], TEditInputOps USING [WaitForInsertToFinish], TEditOps USING [FileNameProc], TEditProfile USING [DefaultMenuChoice, implExtensions, menu1, menu2, menu3, openFirstLevelOnly, sourceExtensions, tryVersionMap], TEditSelection USING [FindRope, fSel, LockSel, MakeSelection, pSel, sSel, UnlockSel], TEditSelectionOps USING [ShowGivenPosition], TextEdit USING [Size], TextNode USING [Location, LocNumber, LocWithin, NarrowToTextNode, nullLocation, Ref, RefTextNode, Root], VersionMap USING [MapList, Range, RangeList, RangeToEntry, ShortNameToRanges], VersionMapDefaults USING [GetMapList], ViewerClasses USING [Column, Viewer], ViewerForkers USING [CallBack, ForkCall, ForkPaint], ViewerGroupLocks USING [CallRootAndLinksUnderWriteLock], ViewerLocks USING [CallUnderColumnLocks], ViewerOps USING [AddProp, CloseViewer, ComputeColumn, CreateViewer, DestroyViewer, EnumerateViewers, EnumProc, EstablishViewerPosition, FetchProp, MoveBelowViewer, OpenIcon, PaintHint, PaintViewer, SaveViewer], ViewerPrivate USING [AcquireWriteLocks, ReleaseWriteLocks], ViewerTools USING [GetContents, GetSelectionContents, SelPos, SelPosRec, SetSelection], WorldVM USING [LocalWorld]; TEditDocuments2Impl: CEDAR MONITOR IMPORTS AMMiniModel, BasicTime, Convert, FS, Menus, MessageWindow, NodeProps, Rope, TEditDocument, TEditDocumentPrivate, TextEdit, TextNode, TEditDisplay, TEditInput, TEditInputOps, TEditProfile, TEditSelection, TEditSelectionOps, VersionMap, VersionMapDefaults, ViewerForkers, ViewerGroupLocks, ViewerLocks, ViewerOps, ViewerPrivate, ViewerTools, WorldVM EXPORTS TEditDocument, TEditDocumentPrivate, TEditOps = BEGIN ROPE: TYPE = Rope.ROPE; Viewer: TYPE = ViewerClasses.Viewer; File: TYPE = FS.OpenFile; noFile: File = FS.nullOpenFile; initialCaret: ViewerTools.SelPos _ NEW[ViewerTools.SelPosRec _ []]; ForceInitialCaret: PROC [viewer: Viewer] = { ViewerTools.SetSelection[viewer, initialCaret]; }; lastRoot: TextNode.Ref; lastViewer: Viewer; GetViewerForRootI: INTERNAL PROC [root: TextNode.Ref] RETURNS [viewer: Viewer] = { IF root = NIL THEN RETURN [NIL]; IF root = lastRoot THEN RETURN [lastViewer]; lastRoot _ root; RETURN [lastViewer _ NARROW[NodeProps.GetProp[root,$Viewer]]]; }; RecordViewerForRootI: INTERNAL PROC [viewer: Viewer, root: TextNode.Ref] = { NodeProps.PutProp[root,$Viewer,viewer]; IF root = lastRoot THEN lastViewer _ viewer; -- keep the cache up to date }; GetViewerForRoot: PUBLIC ENTRY PROC [root: TextNode.Ref] RETURNS [viewer: Viewer] = { ENABLE UNWIND => NULL; RETURN [GetViewerForRootI[root]]; }; RecordViewerForRoot: PUBLIC ENTRY PROC [viewer: Viewer, root: TextNode.Ref] = { ENABLE UNWIND => NULL; RecordViewerForRootI[viewer, root]; }; ForgetViewer: PUBLIC ENTRY PROC [viewer: 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 { RecordViewerForRootI[viewer.link,root]; RETURN; }; RecordViewerForRootI[NIL,root]; }; LoadHistory: TYPE = RECORD[name: ROPE, place: INT]; 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^; }; 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: 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 LoadHistory _ AllocLoadHistory[viewer]; SetLoadHistoryInfo[parent, prop]; }; SaveLoadHistory: PROC [viewer: Viewer] = { prop: REF LoadHistory _ AllocLoadHistory[viewer]; SetLoadHistoryInfo[viewer, prop]; }; PositionHistory: TYPE = TEditDocumentPrivate.PositionHistory; 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 _ 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 _ NEW[PositionHistory]; ViewerOps.AddProp[viewer, $PositionHistory, prop] }; [] _ TEditDocument.SpinAndLock[tdd, "RememberCurrentPosition"]; loc _ tdd.lineTable.lines[0].pos; TEditDocument.Unlock[tdd]; IF loc = prop.pos THEN RETURN; prop.prev _ prop.pos; prop.pos _ loc; }; PositionViewer: PUBLIC PROC [viewer: Viewer, loc: TextNode.Location, hint: ViewerOps.PaintHint _ client] RETURNS [ok: BOOL _ FALSE] = { ok _ PositionViewerInternal[viewer, loc]; IF ok THEN ForkViewerPainter[viewer, hint]; }; PositionViewerInternal: PROC [viewer: Viewer, loc: TextNode.Location] RETURNS [ok: BOOL _ FALSE] = { CheckPosition: PROC [viewer: Viewer, loc: TextNode.Location] RETURNS [good: BOOL, 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]; }; WITH viewer.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { node: TextNode.RefTextNode; [ok, loc] _ CheckPosition[viewer, loc]; IF ok THEN { RememberCurrentPosition[viewer]; IF (node _ TextNode.NarrowToTextNode[loc.node]) # NIL THEN { 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]; }; }; ENDCASE; }; CloseAndForkPaint: PROC [viewer: Viewer] = TRUSTED { ViewerOps.CloseViewer[viewer, FALSE]; ViewerForkers.ForkPaint[viewer, all]; }; ForkViewerPainter: PROC [viewer: Viewer, hint: ViewerOps.PaintHint] = TRUSTED { ViewerForkers.ForkPaint[viewer, hint]; }; ViewerPainter: PROC [viewer: Viewer, hint: ViewerOps.PaintHint] = { ENABLE ABORTED => CONTINUE; ViewerOps.PaintViewer[viewer, hint]; }; KillSelections: PUBLIC PROC [parent: 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]; }; CancelLinks: PUBLIC PROC [viewer: Viewer] = { ForgetViewer[viewer]; IF viewer.link.link=viewer THEN { viewer.link.link _ NIL; ForkViewerPainter[viewer.link, caption]; } ELSE FOR v: Viewer _ viewer.link.link, v.link UNTIL v.link=viewer DO REPEAT FINISHED => v.link _ viewer.link; ENDLOOP; viewer.link _ NIL; }; DefaultMenus: PUBLIC PROC [viewer: Viewer, paint: BOOL _ FALSE] = { menu: Menus.Menu _ viewer.menu; num: INTEGER _ 1; DoLine: PROC [which: TEditProfile.DefaultMenuChoice] = { entry: Menus.MenuEntry _ SELECT which FROM places => TEditDocumentPrivate.findMenu, levels => TEditDocumentPrivate.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 ForkViewerPainter[viewer, all]; }; MakeNewViewer: PROC [parent: Viewer, wDir: ROPE _ NIL] RETURNS [viewer: Viewer] = { viewer _ MakeNewIcon[parent, wDir]; IF parent = NIL THEN ViewerOps.OpenIcon[icon: viewer, paint: TRUE] ELSE { col: ViewerClasses.Column = parent.column; inner: PROC = { IF parent.destroyed THEN RETURN; IF parent.iconic THEN RETURN; IF NOT viewer.iconic THEN RETURN; IF parent.column # col THEN RETURN; viewer.openHeight _ parent.openHeight; ViewerOps.OpenIcon[icon: viewer, paint: FALSE]; ViewerOps.MoveBelowViewer[static: parent, altered: viewer, paint: FALSE]; ViewerOps.ComputeColumn[col]; }; IF TEditProfile.openFirstLevelOnly THEN WITH viewer.data SELECT FROM tdd: TEditDocument.TEditDocumentData => tdd.clipLevel _ 1; ENDCASE; ViewerLocks.CallUnderColumnLocks[inner, col, static]; }; }; MakeNewIcon: PROC [parent: Viewer, wDir: ROPE _ NIL] RETURNS [viewer: Viewer] = { IF wDir=NIL THEN wDir _ WorkingDirectoryFromViewer[parent]; viewer _ ViewerOps.CreateViewer[ flavor: $Text, info: [name: wDir, column: IF parent=NIL THEN left ELSE parent.column, iconic: TRUE], paint: FALSE]; IF TEditProfile.openFirstLevelOnly THEN WITH viewer.data SELECT FROM tdd: TEditDocument.TEditDocumentData => tdd.clipLevel _ 1; ENDCASE; DefaultMenus[viewer]; }; ReplaceByNewViewer: PROC [parent: Viewer, wDir: ROPE _ NIL] RETURNS [viewer: Viewer] = { viewer _ MakeNewIcon[parent, wDir]; SwapViewers[parent, viewer]; }; SwapViewers: PROC [parent: Viewer, icon: Viewer] = { inner: PROC = { IF parent.destroyed THEN RETURN; IF parent.iconic THEN RETURN; IF NOT icon.iconic THEN RETURN; IF parent.column # col THEN RETURN; icon.openHeight _ parent.openHeight; ViewerOps.OpenIcon[icon: icon, paint: FALSE]; ViewerOps.MoveBelowViewer[static: parent, altered: icon, paint: FALSE]; CloseAndForkPaint[parent]; ViewerOps.ComputeColumn[col]; }; col: ViewerClasses.Column = parent.column; KillSelections[parent]; -- need to deselect before making new viewer ViewerLocks.CallUnderColumnLocks[inner, col, static]; }; FindOldViewer: PROC [name: ROPE, viewer: Viewer] RETURNS [old: Viewer _ NIL] = { Match: ViewerOps.EnumProc -- PROC[v: Viewer] RETURNS[BOOL _ TRUE] -- = { IF v#viewer AND Rope.Equal[name, v.name, FALSE] THEN { old _ v; RETURN [FALSE] }; }; ViewerOps.EnumerateViewers[Match]; }; Report: PROC [m1, m2, m3, m4: ROPE _ NIL, flash: BOOL _ FALSE] = { ENABLE ABORTED => CONTINUE; MessageWindow.Append[m1, TRUE]; IF m2#NIL THEN MessageWindow.Append[m2]; IF m3#NIL THEN MessageWindow.Append[m3]; IF m4#NIL THEN MessageWindow.Append[m4]; IF flash THEN MessageWindow.Blink[]; }; Flash: PROC [m1, m2: ROPE _ NIL] = { Report[m1: m1, m2: m2, flash: TRUE]; }; PleaseSelectFileName: PROC = { Flash["Please select file name."]; }; IllegalFileName: ViewerForkers.CallBack = { Flash["Illegal file name."]; }; ReloadedMessage: ViewerForkers.CallBack = { WITH data SELECT FROM name: ROPE => Flash[name," restored with previous unsaved edits."]; ENDCASE; }; RemoveVersion: PROC [x: ROPE] RETURNS [ROPE] = { RETURN [x.Flatten[len: x.SkipTo[skip: "!"]]]; }; 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 _ RemoveVersion[name]; }; LoadOp: TYPE ~ {load, open, replace}; LookupType: TYPE ~ {source, impl}; DoGet: PROC [parent: Viewer, file: FS.OpenFile, specificVersion: BOOL, op: LoadOp _ $load, place: INT _ 0, search: ROPE _ NIL, forceOpen: BOOL _ TRUE] RETURNS [viewer: Viewer] = { viewerIn: Viewer _ parent; needPaint: BOOL _ FALSE; loaded: BOOL _ FALSE; IF parent = NIL THEN op _ open; SELECT op FROM load => viewerIn _ parent; open => viewerIn _ MakeNewIcon[parent]; replace => viewerIn _ ReplaceByNewViewer[parent]; ENDCASE => ERROR; [viewer, loaded] _ DoLoad[viewer: viewerIn, file: file, op: op, specificVersion: specificVersion, place: place]; IF viewer # NIL THEN { IF viewer # viewerIn THEN { Report[viewer.name, " was already loaded."]; SELECT op FROM open, replace => TRUSTED { ViewerForkers.ForkCall[viewerIn, FlameOut, viewerIn]; viewerIn _ NIL}; ENDCASE; }; IF Rope.Size[search] # 0 THEN WITH viewer.data SELECT FROM ntdd: TEditDocument.TEditDocumentData => { loc: TextNode.Location _ TextNode.LocWithin[ntdd.text, 0]; sel: TEditDocument.Selection _ NIL; IF Rope.Match["|*", search] THEN { pos: INT _ Convert.IntFromRope[Rope.Flatten[search, 1] ! Convert.Error => GO TO faulty]; nloc: TextNode.Location _ TextNode.LocWithin[n: ntdd.text, count: pos, skipCommentNodes: TRUE]; [] _ PositionViewerInternal[viewer, nloc]; TEditSelectionOps.ShowGivenPosition[viewer, pos]; EXITS faulty => {}; } ELSE { TEditDisplay.EstablishLine[ntdd, loc]; TEditSelection.FindRope[ viewer: viewer, rope: search, case: TRUE, word: TRUE, def: TRUE, id: feedback]; sel _ TEditSelection.fSel; IF sel # NIL AND sel.viewer = viewer THEN loc _ sel.start.pos; TEditDisplay.EstablishLine[ntdd, loc]; }; RememberCurrentPosition[viewer]; needPaint _ TRUE; }; ENDCASE; SELECT TRUE FROM viewer.iconic AND forceOpen => { ViewerOps.OpenIcon[viewer]; IF parent # NIL AND parent # viewer AND NOT parent.destroyed THEN IF op = replace THEN CloseAndForkPaint[parent] ELSE ViewerOps.MoveBelowViewer[viewer, parent, TRUE]; }; loaded => ForkViewerPainter[viewer, all]; needPaint => ForkViewerPainter[viewer, client]; ENDCASE; }; }; DoLoad: PROC [viewer: Viewer, file: FS.OpenFile, op: LoadOp, specificVersion: BOOL _ FALSE, place: INT _ 0] RETURNS [out: Viewer, loaded: BOOL _ FALSE] = { clearMessage: BOOL _ TRUE; fileName: ROPE ~ FS.GetName[file].fullFName; name: ROPE _ fileName; out _ viewer; IF NOT specificVersion THEN name _ name.Flatten[len: name.SkipTo[skip: "!"]]; IF Rope.Equal[viewer.file, fileName, FALSE] THEN { Report[fileName, " is already loaded."]; RETURN; }; Report["Loading ", name]; KillSelections[viewer]; WITH viewer.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { oldViewer: Viewer _ NIL; linkViewer: Viewer _ NIL; vFile: ROPE _ NIL; DO oldViewer _ FindOldViewer[name, viewer]; IF oldViewer # NIL THEN linkViewer _ oldViewer.link; ViewerPrivate.AcquireWriteLocks[viewer, oldViewer, linkViewer]; IF oldViewer = FindOldViewer[name, viewer] AND (oldViewer = NIL OR linkViewer = oldViewer.link) THEN EXIT; ViewerPrivate.ReleaseWriteLocks[viewer, oldViewer, linkViewer]; ENDLOOP; { ENABLE UNWIND => ViewerPrivate.ReleaseWriteLocks[viewer, oldViewer, linkViewer]; [] _ TEditDocument.SpinAndLock[tdd, "DoLoad"]; IF (vFile _ viewer.file) #NIL THEN SaveLoadHistory[viewer]; IF oldViewer # NIL THEN { IF NOT oldViewer.destroyed THEN WITH oldViewer.data SELECT FROM tddOld: TEditDocument.TEditDocumentData => GO TO oldCase; ENDCASE; EXITS oldCase => {}; }; SELECT TRUE FROM oldViewer = NIL => { root: TextNode.Ref ~ TEditDocumentPrivate.FindUnsavedDocument[fileName]; IF viewer.link=NIL THEN { ForgetViewer[viewer]; -- remove this from the root => viewer mapping IF viewer.newVersion AND (NOT viewer.saveInProgress) AND vFile#NIL THEN TEditDocumentPrivate.RecordUnsavedDocument[vFile, tdd.text] ELSE TEditInput.FreeTree[tdd.text]; } ELSE CancelLinks[viewer]; viewer.name _ name; viewer.file _ fileName; viewer.newVersion _ viewer.newFile _ FALSE; IF root # NIL THEN { ViewerForkers.ForkCall[NIL, ReloadedMessage, name]; clearMessage _ FALSE; }; tdd.text _ NIL; -- so InitViewerDoc won't worry about freeing it TEditDocumentPrivate.InitViewerDocInternal[viewer, file, root]; viewer.newFile _ FALSE; viewer.newVersion _ root#NIL; loaded _ TRUE; ClearPositionHistory[viewer]; [] _ PositionViewerInternal[viewer, TextNode.LocWithin[tdd.text, place]]; RememberCurrentPosition[viewer]; }; ENDCASE => { out _ oldViewer; }; TEditDocument.Unlock[tdd]; ViewerPrivate.ReleaseWriteLocks[viewer, oldViewer, linkViewer]; }; IF clearMessage THEN MessageWindow.Clear[]; }; ENDCASE; }; FlameOut: ViewerForkers.CallBack = { ENABLE ABORTED => CONTINUE; WITH data SELECT FROM v: Viewer => ViewerOps.DestroyViewer[v]; ENDCASE; }; TryToOpen: PROC [name: ROPE, wDir: ROPE _ NIL] RETURNS [file: FS.OpenFile _ FS.nullOpenFile] = { file _ FS.Open[name: name, wDir: wDir ! FS.Error => IF error.code=$unknownFile THEN CONTINUE]; }; TryExtensions: PROC [name: ROPE, wDir: ROPE, extensions: LIST OF ROPE] RETURNS [file: FS.OpenFile _ FS.nullOpenFile] = { base: ROPE ~ name.Concat["."]; FOR list: LIST OF ROPE _ extensions, list.rest UNTIL list=NIL DO file _ TryToOpen[name: base.Concat[list.first], wDir: wDir]; IF file#FS.nullOpenFile THEN EXIT; ENDLOOP; }; IsAnExtension: PROC [ext: ROPE, extensions: LIST OF ROPE] RETURNS [BOOL] = { FOR list: LIST OF ROPE _ extensions, list.rest UNTIL list=NIL DO IF Rope.Equal[ext, list.first, FALSE] THEN RETURN [TRUE]; ENDLOOP; RETURN [FALSE]; }; FileNameProc: TYPE = TEditOps.FileNameProc; fileNameProc: FileNameProc _ NIL; RegisterFileNameProc: PUBLIC PROC [proc: FileNameProc] = { fileNameProc _ proc; }; ReplaceFileNameProc: PUBLIC PROC [new: FileNameProc] RETURNS [old: FileNameProc] = { old _ fileNameProc; fileNameProc _ new; }; TryVersionMap: PROC [shortName: ROPE] RETURNS [file: FS.OpenFile _ FS.nullOpenFile] = { mapList: VersionMap.MapList ~ VersionMapDefaults.GetMapList[$Source]; ranges: VersionMap.RangeList ~ VersionMap.ShortNameToRanges[mapList, shortName]; bestName: ROPE _ NIL; bestDate: BasicTime.GMT _ BasicTime.nullGMT; FOR list: VersionMap.RangeList _ ranges, list.rest UNTIL list=NIL DO range: VersionMap.Range _ list.first; WHILE range.len # 0 DO fullName: ROPE; created: BasicTime.GMT; [name: fullName, created: created, next: range] _ VersionMap.RangeToEntry[range]; IF bestDate = BasicTime.nullGMT OR BasicTime.Period[from: bestDate, to: created] > 0 THEN {bestDate _ created; bestName _ fullName}; ENDLOOP; ENDLOOP; IF bestName # NIL THEN RETURN [FS.Open[name: bestName, wantedCreatedTime: bestDate]]; }; TryVersionMapExtensions: PROC [name: ROPE, extensions: LIST OF ROPE] RETURNS [file: FS.OpenFile _ FS.nullOpenFile] = { base: ROPE ~ name.Concat["."]; FOR list: LIST OF ROPE _ extensions, list.rest UNTIL list=NIL DO file _ TryVersionMap[base.Concat[list.first]]; IF file#FS.nullOpenFile THEN EXIT; ENDLOOP; }; FileNotFound: ERROR[fileName: ROPE] = CODE; LookupSource: PROC [sel: ROPE, wDir: ROPE, fileNameProcViewer: Viewer _ NIL] RETURNS [file: FS.OpenFile _ FS.nullOpenFile, specificVersion: BOOL _ FALSE, search: ROPE _ NIL] = { dot: INT _ 0; hasExtension, standardExtension, simpleName: BOOL _ FALSE; base, ext: ROPE _ NIL; proc: FileNameProc ~ fileNameProc; Report["Directory lookup for ", sel]; FOR i: INT DECREASING IN[0..sel.Size[]) DO SELECT sel.Fetch[i] FROM '| => {search _ Rope.Flatten[sel, i]; sel _ Rope.Flatten[sel, 0, i]; EXIT}; IN ['0..'9] => {}; ENDCASE => EXIT; ENDLOOP; FOR i: INT DECREASING IN[0..sel.Size[]) DO SELECT sel.Fetch[i] FROM '! => specificVersion _ TRUE; '. => IF hasExtension THEN NULL ELSE { dot _ i; hasExtension _ TRUE }; '], '>, '/ => EXIT; ENDCASE; REPEAT FINISHED => simpleName _ TRUE; ENDLOOP; file _ TryToOpen[name: sel, wDir: wDir]; IF file#FS.nullOpenFile THEN RETURN; IF hasExtension OR specificVersion THEN NULL ELSE { file _ TryExtensions[name: sel, wDir: wDir, extensions: TEditProfile.sourceExtensions]; IF file#FS.nullOpenFile THEN RETURN; }; IF proc#NIL THEN { pname, psearch: ROPE; [pname, psearch] _ proc[sel, fileNameProcViewer]; IF pname.Size[]#0 THEN { file _ TryToOpen[name: pname, wDir: wDir]; IF file#FS.nullOpenFile THEN { search _ psearch; RETURN }; }; }; IF specificVersion THEN RETURN; IF hasExtension THEN { base _ sel.Substr[len: dot]; ext _ sel.Substr[start: dot+1]; IF IsAnExtension[ext, TEditProfile.sourceExtensions] THEN standardExtension _ TRUE; IF NOT standardExtension THEN { file _ TryExtensions[name: base, wDir: wDir, extensions: TEditProfile.implExtensions]; IF file#FS.nullOpenFile THEN { search _ ext; RETURN }; }; }; IF simpleName AND TEditProfile.tryVersionMap THEN { Report["Get: trying version map for ", sel]; file _ TryVersionMap[sel]; -- try sel verbatim first IF file#FS.nullOpenFile THEN RETURN; IF NOT hasExtension THEN { file _ TryVersionMapExtensions[sel, TEditProfile.sourceExtensions]; IF file#FS.nullOpenFile THEN RETURN; } ELSE IF NOT standardExtension THEN { file _ TryVersionMapExtensions[base, TEditProfile.implExtensions]; IF file#FS.nullOpenFile THEN { search _ ext; RETURN }; }; }; }; LookupImpl: PROC [sel: ROPE, wDir: ROPE] RETURNS [file: FS.OpenFile _ FS.nullOpenFile, search: ROPE _ NIL] = { cp: FS.ComponentPositions; simpleName: BOOL ~ sel.SkipTo[skip: "[]<>/"]=sel.Size[]; xname, base, ext, impl: ROPE _ NIL; [fullFName: xname, cp: cp] _ FS.ExpandName[name: sel, wDir: wDir]; base _ xname.Substr[start: cp.base.start, len: cp.base.length]; -- base part is defs name ext _ xname.Substr[start: cp.ext.start, len: cp.ext.length]; -- extension part is search item IF ext.Size[]#0 THEN { Report["Model lookup for implementor of ", base, ".", ext]; TRUSTED{ impl _ AMMiniModel.ImplementorName[ defsName: base, itemName: ext, world: WorldVM.LocalWorld[]] }; }; IF impl=NIL THEN impl _ base.Concat["Impl"]; Report["Directory lookup for ", impl]; file _ TryExtensions[name: impl, wDir: xname.Substr[len: cp.base.start], extensions: TEditProfile.implExtensions]; IF file#FS.nullOpenFile THEN { search _ ext; RETURN }; IF simpleName AND TEditProfile.tryVersionMap THEN { Report["GetImpl: trying version map for ", impl]; file _ TryVersionMapExtensions[impl, TEditProfile.implExtensions]; IF file#FS.nullOpenFile THEN { search _ ext; RETURN }; }; ERROR FileNotFound[impl]; }; WorkingDirectoryFromViewer: PUBLIC PROC [parent: Viewer] RETURNS [ROPE] = { name, fname: ROPE _ NIL; cp: FS.ComponentPositions; IF parent#NIL THEN name _ parent.name; { ENABLE FS.Error => CONTINUE; IF name=NIL OR parent.file=NIL THEN [fullFName: fname, cp: cp] _ FS.ExpandName[name: "*", wDir: name ! FS.Error => CONTINUE] ELSE [fullFName: fname, cp: cp] _ FS.ExpandName[name: name ! FS.Error => CONTINUE]; RETURN [fname.Substr[len: cp.base.start]]; }; RETURN [FS.GetDefaultWDir[]]; }; IsAWorkingDirectory: PROC [name: ROPE] RETURNS [BOOL] = { RETURN [Rope.Match["*/", name] OR Rope.Match["*>", name]]; }; CanonicalWorkingDirectory: PROC [txt: ROPE, wDir: ROPE _ NIL] RETURNS [ROPE] = { fname: ROPE _ NIL; cp: FS.ComponentPositions; [fullFName: fname, cp: cp] _ FS.ExpandName[name: txt.Concat["*"], wDir: wDir ! FS.Error => CONTINUE]; IF fname=NIL THEN RETURN [NIL] ELSE RETURN [fname.Substr[len: cp.base.start]]; }; DoGetFile: PROC [txt: ROPE, parent: Viewer, op: LoadOp _ $load, lookup: LookupType _ $source, fileNameProcViewer: Viewer _ NIL] RETURNS [viewer: Viewer _ NIL] = { parentDir: ROPE ~ WorkingDirectoryFromViewer[parent]; file: FS.OpenFile _ FS.nullOpenFile; specificVersion: BOOL _ FALSE; search: ROPE _ NIL; IF txt=NIL THEN txt _ ViewerTools.GetSelectionContents[]; IF fileNameProcViewer=NIL THEN fileNameProcViewer _ parent; IF txt.Size[]=0 THEN { PleaseSelectFileName[]; GOTO Fail }; IF IsAWorkingDirectory[txt] THEN { wDir: ROPE ~ CanonicalWorkingDirectory[txt, parentDir]; IF wDir=NIL THEN { Flash[txt, " is an illegal working directory."]; GOTO Fail }; SELECT op FROM load => DoEmptyViewer[parent: viewer _ parent, wDir: wDir]; open => viewer _ MakeNewViewer[parent: parent, wDir: wDir]; replace => viewer _ ReplaceByNewViewer[parent: parent, wDir: wDir]; ENDCASE => ERROR; RETURN [viewer]; }; { ENABLE { FS.Error => { Flash[error.explanation]; GOTO Fail }; FileNotFound => { Flash[fileName, " not found."]; GOTO Fail }; }; SELECT lookup FROM $source => [file: file, specificVersion: specificVersion, search: search] _ LookupSource[sel: txt, wDir: parentDir, fileNameProcViewer: fileNameProcViewer]; $impl => [file: file, search: search] _ LookupImpl[sel: txt, wDir: parentDir]; ENDCASE => ERROR; IF file=FS.nullOpenFile THEN { Flash[txt, " not found."]; GOTO Fail }; }; viewer _ DoGet[parent, file, specificVersion, op, 0, search]; EXITS Fail => RETURN [NIL]; }; DoEmptyViewer: PROC [parent: Viewer, wDir: ROPE _ NIL] = { inner: PROC [tdd: TEditDocument.TEditDocumentData] = { link1: Viewer _ parent.link; link2: Viewer _ NIL; IF wDir=NIL THEN wDir _ WorkingDirectoryFromViewer[parent]; TEditSelection.LockSel[primary, "EmptyViewer"]; { ENABLE UNWIND => TEditSelection.UnlockSel[primary]; prop: REF LoadHistory; [] _ TEditDocument.SpinAndLock[tdd, "EmptyViewer"]; KillSelections[parent]; SaveLoadHistory[parent]; prop _ NARROW[ViewerOps.FetchProp[parent, $LoadHistory]]; -- hang onto it SELECT TRUE FROM link1 # NIL => CancelLinks[parent]; parent.newVersion AND ~parent.saveInProgress AND parent.file # NIL => TEditDocumentPrivate.RecordUnsavedDocument[parent.file, tdd.text]; ENDCASE => TEditInput.FreeTree[tdd.text]; parent.name _ wDir; parent.file _ NIL; parent.newVersion _ parent.newFile _ FALSE; tdd.text _ NIL; -- so InitViewerDoc won't free it TEditDocumentPrivate.InitViewerDoc[parent,NIL]; TEditDocument.Unlock[tdd]; ClearPositionHistory[parent]; ViewerOps.AddProp[parent, $LoadHistory, prop]; -- restore file history ViewerPainter[parent, all]; ForceInitialCaret[parent]; }; TEditSelection.UnlockSel[primary]; }; IF parent # NIL THEN LockTheWorks[inner, parent, "EmptyViewer"]; }; EmptyViewer: PUBLIC PROC [parent: Viewer] = { DoEmptyViewer[parent]; }; DoNewViewer: PUBLIC PROC [parent: Viewer _ NIL] RETURNS [new: Viewer] = { TEditSelection.LockSel[primary, "DoNewViewer"]; { ENABLE UNWIND => TEditSelection.UnlockSel[primary]; new _ MakeNewViewer[parent]; ForceInitialCaret[new]; }; TEditSelection.UnlockSel[primary]; }; NewViewer: PUBLIC PROC [parent: Viewer] = { [] _ DoNewViewer[parent]; }; DoCloseAndNewViewer: PUBLIC PROC [parent: Viewer] RETURNS [new: Viewer] = { TEditSelection.LockSel[primary, "DoCloseAndNewViewer"]; { ENABLE UNWIND => TEditSelection.UnlockSel[primary]; new _ ReplaceByNewViewer[parent]; ForceInitialCaret[new]; }; TEditSelection.UnlockSel[primary]; }; CloseAndNewViewer: PUBLIC PROC [parent: Viewer] = { [] _ DoCloseAndNewViewer[parent]; }; DoLoadFile: PUBLIC PROC [parent: Viewer, fileName: ROPE _ NIL, close: BOOL _ FALSE, fileNameProcViewer: Viewer _ NIL] RETURNS [viewer: Viewer] = { viewer _ DoGetFile[txt: fileName, parent: parent, op: IF close THEN $replace ELSE $load, lookup: $source, fileNameProcViewer: fileNameProcViewer]; }; LoadFile: PUBLIC PROC [parent: Viewer] = { [] _ DoLoadFile[parent: parent, fileName: NIL, close: FALSE]; }; DoOpenFile: PUBLIC PROC [fileName: ROPE _ NIL, parent: Viewer, fileNameProcViewer: Viewer _ NIL] RETURNS [viewer: Viewer] = { viewer _ DoGetFile[ txt: fileName, parent: parent, op: $open, lookup: $source, fileNameProcViewer: fileNameProcViewer]; }; OpenFile: PUBLIC PROC [parent: Viewer] = { [] _ DoOpenFile[fileName: NIL, parent: parent]; }; DoCloseAndOpenFile: PUBLIC PROC [parent: Viewer, fileName: ROPE _ NIL] RETURNS [viewer: Viewer] = { viewer _ DoGetFile[txt: fileName, parent: parent, op: $replace, lookup: $source]; }; CloseAndOpenFile: PUBLIC PROC [parent: Viewer, fileNameProcViewer: Viewer _ NIL] = { [] _ DoGetFile[txt: NIL, parent: parent, op: $replace, lookup: $source, fileNameProcViewer: fileNameProcViewer]; }; DoLoadImplFile: PUBLIC PROC [parent: Viewer, fileName: ROPE _ NIL, close: BOOL _ FALSE] RETURNS [viewer: Viewer] = { viewer _ DoGetFile[txt: fileName, parent: parent, op: IF close THEN $replace ELSE $load, lookup: $impl]; }; LoadImplFile: PUBLIC PROC [parent: Viewer] = { [] _ DoLoadImplFile[parent: parent, fileName: NIL]; }; DoOpenImplFile: PUBLIC PROC [fileName: ROPE _ NIL, parent: Viewer _ NIL] RETURNS [viewer: Viewer] = { viewer _ DoGetFile[txt: fileName, parent: parent, op: $open, lookup: $impl]; }; OpenImplFile: PUBLIC PROC [parent: Viewer] = { [] _ DoOpenImplFile[fileName: NIL, parent: parent]; }; DoCloseAndOpenImplFile: PUBLIC PROC [parent: Viewer, fileName: ROPE _ NIL] RETURNS [viewer: Viewer] = { viewer _ DoGetFile[txt: fileName, parent: parent, op: $replace, lookup: $impl]; }; CloseAndOpenImplFile: PUBLIC PROC [parent: Viewer] = { [] _ DoCloseAndOpenImplFile[parent, NIL]; }; PreLoadPrevious: PUBLIC Menus.MenuProc = { -- called when unguarding PrevFile viewer: Viewer = NARROW[parent]; tdd: TEditDocument.TEditDocumentData; prop: REF LoadHistory; propName: ROPE; tdd _ NARROW[viewer.data]; IF tdd = NIL THEN RETURN; [] _ TEditDocument.SpinAndLock[tdd, "PreLoadPrevious"]; prop _ NARROW[ViewerOps.FetchProp[viewer, $LoadHistory]]; TEditDocument.Unlock[tdd]; IF prop=NIL OR Rope.Equal[prop.name, viewer.file, FALSE] THEN { Flash["No record of previous file loaded in this viewer"]; RETURN; }; propName _ prop.name; Report[propName," ~ Click LEFT to load, MIDDLE for new, RIGHT for close & new"]; }; DoLoadPreviousFile: PROC [parent: Viewer, op: LoadOp] = { WITH parent.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { prop: REF LoadHistory; propName: ROPE; propPlace: INT; file: FS.OpenFile; [] _ TEditDocument.SpinAndLock[tdd, "DoLoadPreviousFile"]; prop _ NARROW[ViewerOps.FetchProp[parent, $LoadHistory]]; TEditDocument.Unlock[tdd]; IF prop = NIL OR Rope.Equal[prop.name, parent.file, FALSE] THEN { Flash["No record of previous file loaded in this viewer"]; RETURN }; propName _ prop.name; propPlace _ prop.place; file _ FS.Open[propName ! FS.Error => { Flash[error.explanation]; GOTO Fail }]; [] _ DoGet[parent: parent, file: file, specificVersion: (propName.Find["!"]>=0), op: op, place: propPlace, forceOpen: FALSE]; }; ENDCASE; EXITS Fail => NULL; }; LoadPreviousFile: PUBLIC PROC [parent: Viewer] = { DoLoadPreviousFile[parent: parent, op: $load]; }; OpenPreviousFile: PUBLIC PROC [parent: Viewer] = { DoLoadPreviousFile[parent: parent, op: $open]; }; CloseAndOpenPreviousFile: PUBLIC PROC [parent: Viewer] = { DoLoadPreviousFile[parent: parent, op: $replace]; }; GetCreateName: PROC [parent: Viewer, name: ROPE] RETURNS [ROPE _ NIL] = { wDir: ROPE ~ WorkingDirectoryFromViewer[parent]; fullFName: ROPE; cp: FS.ComponentPositions; [fullFName: fullFName, cp: cp] _ FS.ExpandName[name, wDir ! FS.Error => GOTO Fail]; RETURN [Rope.Flatten[base: fullFName, len: cp.ext.start+cp.ext.length]]; -- strip version EXITS Fail => ViewerForkers.ForkCall[NIL, IllegalFileName]; }; IsNewFile: PROC [name: ROPE] RETURNS [new: BOOL _ FALSE] = { [] _ FS.FileInfo[name ! FS.Error => { new _ TRUE; CONTINUE }]; }; PreStore: PUBLIC Menus.MenuProc = { -- called when unguarding Store sel: ROPE _ ViewerTools.GetSelectionContents[]; fileName: ROPE _ NIL; new: BOOL _ FALSE; IF sel.Size[]=0 THEN {PleaseSelectFileName[]; RETURN}; fileName _ GetCreateName[NARROW[parent], sel]; IF fileName=NIL THEN RETURN; new _ IsNewFile[fileName]; Report["Confirm Store to file: ", fileName, IF new THEN " [New File]" ELSE " [Old File]"]; }; DoStoreFile: PUBLIC PROC [parent: Viewer, fileName: ROPE _ NIL] = { inner: PROC [tdd: TEditDocument.TEditDocumentData] = { linked: BOOL _ parent.link#NIL; oldName: ROPE ~ parent.name; oldFile: ROPE ~ parent.file; IF fileName=NIL THEN fileName _ ViewerTools.GetSelectionContents[]; IF fileName.Size[]=0 THEN {PleaseSelectFileName[]; RETURN}; fileName _ GetCreateName[parent, fileName]; IF fileName=NIL THEN RETURN; IF parent.file # NIL THEN SaveLoadHistory[parent]; IF linked 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 ViewerOps.SaveViewer[parent ! UNWIND => { parent.name _ oldName; parent.file _ oldFile }]; IF linked THEN { loc: INT; KillSelections[parent]; loc _ TextNode.LocNumber[tdd.lineTable.lines[0].pos]; tdd.text _ NIL; -- so InitViewerDoc won't free it TEditDocumentPrivate.InitViewerDoc[parent, NIL]; RememberCurrentPosition[parent]; ForkViewerPainter[parent, caption]; }; }; LockTheWorks[inner, parent, "StoreFile"]; }; LockTheWorks: PROC [inner: PROC [tdd: TEditDocument.TEditDocumentData], viewer: Viewer, who: ROPE] = { innerWorks: PROC = { WITH viewer.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { [] _ TEditDocument.SpinAndLock[tdd, who]; inner[tdd ! UNWIND => TEditDocument.Unlock[tdd]]; TEditDocument.Unlock[tdd]; } ENDCASE }; ViewerGroupLocks.CallRootAndLinksUnderWriteLock[innerWorks, viewer]; }; StoreFile: PUBLIC PROC [parent: Viewer] = { DoStoreFile[parent: parent, fileName: NIL]; }; GetViewerContents: PROC [viewer: Viewer] RETURNS [ROPE] = { TEditInputOps.WaitForInsertToFinish[]; RETURN [ViewerTools.GetContents[viewer]]; }; DoAnonymousLoadFile: PROC [parent: Viewer, lookup: LookupType, fileNameProcViewer: Viewer _ NIL] = { IF parent.file#NIL THEN Flash["Viewer already contains a file."] ELSE { txt: ROPE ~ GetViewerContents[parent]; size: INT ~ txt.Size[]; IF size=0 THEN Flash["Enter a file name."] ELSE { v: Viewer _ DoGetFile[txt: txt, parent: parent, op: $load, lookup: lookup, fileNameProcViewer: fileNameProcViewer]; IF v#NIL AND v#parent THEN ViewerForkers.ForkCall[parent, FlameOut, parent]; }; }; }; AnonymousLoadFile: PUBLIC PROC [parent: Viewer, fileNameProcViewer: Viewer _ NIL] = { DoAnonymousLoadFile[parent: parent, lookup: $source, fileNameProcViewer: fileNameProcViewer]; }; AnonymousLoadImplFile: PUBLIC PROC [parent: Viewer] = { DoAnonymousLoadFile[parent: parent, lookup: $impl]; }; NodeProps.Register[$Viewer, NodeProps.NullRead, NodeProps.NullWrite, NodeProps.NullCopy]; NodeProps.Register[$LockedViewer, 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 Copyright c 1985 by Xerox Corporation. All rights reserved. Plass, April 8, 1985 5:20:37 pm PST Doug Wyatt, June 20, 1985 3:23:59 pm PDT Russ Atkinson (RRA) June 25, 1985 2:12:21 am PDT Michael Plass, March 11, 1986 1:06:03 pm PST change to a linked viewer Make viewer's load history point to current contents of parent backup to line start All calls in this module to ViewerOps.PaintViewer go through here to aid debugging. (note that calls to ComputeColumn also paint the screen) Makes a new, empty, $Text viewer, placing it under the parent viewer (if any). copy height and position info from old to new ... returns a new iconic $Text viewer with default menus, no painting done. Must lock both columns copy height and position info from old to new We were able to do the load Humph! A previous viewer existed! We created a viewer to hold the result, but we will never use it now. We need to perform a search for the given definition. This is a position spec to parse This is a definition to search for capture the location found and establish it as the place to display RRA: For some stupid reason we have to open the icon first before moving things. I wonder why? Load a file into a viewer viewer is the viewer to be loaded with the contents of the file name is the specified name for the file file is the open file Note that if anything changed while we were waiting for the lock we should release our locks, then go around and try again Can this deadlock? We hope not! An old viewer was found, so don't do the load! There is no other viewer with the same name Another viewer has this name, so return it (caller will handle this case) Adapted from VersionMapCommandsImpl.FindSource. Stops at the first name it finds, if any. The first pass is for the position specification (if any) The following are the top level procedures that implement the Tioga file operations: they are available as menu items, system buttons, or keystrokes (LF). Clear: EmptyViewer[viewer] NewViewer[viewer] CloseAndNewViewer[viewer] Reset: TEditDocuments3Impl.ResetOp[viewer] Get: [] _ DoLoadFile[viewer, selection, FALSE] [] _ DoOpenFile[selection, viewer] [] _ DoCloseAndOpenFile[viewer, selection] GetImpl: [] _ DoLoadImplFile[viewer, selection, FALSE] [] _ DoOpenImplFile[selection, viewer] [] _ DoCloseAndOpenImplFile[viewer, selection] PrevFile: LoadPreviousFile[viewer] OpenPreviousFile[viewer] CloseAndOpenPreviousFile[viewer] Store: DoStoreFile[viewer, selection] Save: TEditDocuments3Impl.SaveOp[viewer] New button: NewViewer[NIL] Open button: [] _ DoOpenFile[NIL, selection] LF keyboard command: AnonymousLoadFile[viewer] AnonymousLoadImplFile[viewer] delay until after other op completes delay until after other op completes copy tdd.text data structure Ê+2˜codešœ™Kšœ Ïmœ1™˜QKšœžœz˜”Kšœ žœ ˜Kšœžœ˜,Kšœ žœ˜Kšœ žœo˜KšœžœA˜UKšœžœ˜,Kšœ žœ˜Kšœ žœZ˜hKšœ žœ>˜NKšœžœ˜&Kšœžœ˜%Kšœžœ!˜4Kšœžœ"˜8Kšœ žœ˜)Kšœ žœÃ˜ÒKšœžœ(˜;Kšœ žœF˜WKšœžœ˜—K˜šÐblœžœž˜"Kšžœ"žœ¸˜ãKšžœ.˜5Kšœž˜K˜Kšžœžœžœ˜Kšœžœ˜$Kšœžœžœ ˜Kšœžœ˜K˜—šœ#žœ˜CK˜—šÏnœžœ˜,Kšœ/˜/Kšœ˜K˜—K˜šœ˜K˜—š œžœžœžœ˜RKš žœžœžœžœžœ˜ Kšžœžœžœ˜,K˜Kšžœžœ#˜>Kšœ˜K˜—š œžœžœ)˜LK˜'KšžœžœÏc˜IK˜K˜—š  œžœžœžœžœ˜UKšžœžœžœ˜Kšžœ˜!Kšœ˜K˜—š œžœžœžœ)˜OKšžœžœžœ˜K˜#K˜K˜—š  œžœžœžœ˜4Kšžœžœžœ˜Kšœ'žœ˜;K˜Kšžœžœžœžœ˜K˜Kšžœ"žœžœ˜0šžœžœžœ˜Kšœ™K˜'Kšžœ˜Kšœ˜—Kšœžœ˜Kšœ˜—K˜š œ žœžœžœ žœ˜3K˜—š œžœžœ˜3Kšœžœžœ*˜GKšœžœžœ(˜EKšžœžœžœžœ˜šžœžœžœ˜Kšœžœ˜Kšœ+˜+—K˜ K˜K˜—š œžœžœžœ˜KKš žœ žœ/žœžœžœ˜PKšœžœ˜Kšœ.˜.K˜K˜—š œžœžœ˜DKšœ'žœ˜;Kšžœžœžœžœ˜Kšœ˜K˜Kšœžœ(˜1Kšœ!˜!Kšœ˜K˜—š œžœ˜*Kšœžœ(˜1Kšœ!˜!Kšœ˜—K˜šœžœ(˜=K˜—š œžœžœ˜7Kšœžœžœ.˜OKšœžœžœ,˜MKšžœžœžœžœ˜šžœžœžœ˜Kšœžœ˜K˜-K˜—K˜ K˜K˜—š œžœ˜/Kšœžœžœ0˜RKšžœžœžœžœ˜K˜-K˜K˜—š œžœžœ˜9Kšœ'žœ˜;Kšœžœžœ0˜RK˜Kšžœžœžœžœ˜šžœžœžœ˜Kšœžœ˜K˜4—Kšœ?˜?K˜!Kšœ˜Kšžœžœžœ˜K˜%K˜K˜—š  œžœžœNžœžœžœ˜‡Kšœ)˜)Kšžœžœ!˜+K˜K˜—š  œžœ*žœžœžœ˜dš  œžœ*žœžœ!˜qK˜K˜Kšœ%˜%Kšžœžœžœžœžœžœžœ˜LKš žœžœžœžœžœ˜6Kšžœžœžœžœ˜*Kšžœžœžœ ¡˜Nš žœ(žœžœ žœžœž˜]Kšžœžœ ˜—Kšžœžœ˜Kšžœ žœžœ˜6K˜—šžœ žœž˜šœ)˜)K˜K˜'šžœžœ˜ K˜ šžœ0žœžœ˜K˜Kšžœ˜—K˜K˜—K˜%K˜—K˜—Kšžœ˜—K˜K˜—š œžœžœ˜4Kšœžœ˜%Kšœ%˜%K˜K˜—š œžœ/žœ˜OKšœ&˜&K˜K˜—š  œžœ0˜CKšžœžœžœ˜šœS™SK™8—Kšœ$˜$K˜K˜—š œžœžœ˜0Kšžœ˜Kšžœžœžœžœ#˜NKšžœžœžœžœ%˜PKšžœžœžœžœ$˜OKšœ˜K˜—š  œžœžœ˜-K˜šžœ˜šžœ˜Kšœžœ˜K˜(Kšœ˜—šžœžœ&žœž˜DKšžœžœ˜(Kšžœ˜——Kšœžœ˜Kšœ˜K˜—š   œžœžœžœžœ˜CK˜Kšœžœ˜š œžœ,˜8šœžœž˜*Kšœ(˜(Kšœ)˜)Kšžœžœ˜—Kšžœ žœžœžœ˜K˜ K˜—K˜K˜K˜K˜VKšžœžœ ˜-Kšœ˜—K˜š   œžœžœžœžœ˜SK™NKšœ#˜#šžœ ž˜Kšžœ)žœ˜2šžœ˜Kšœ*˜*šœžœ˜Kšžœžœžœ˜ Kšžœžœžœ˜Kšžœžœžœžœ˜!Kšžœžœžœ˜#K™-Kšœ&˜&Kšœ(žœ˜/KšœBžœ˜IKšœ˜K˜—šžœ!ž˜'šžœ žœž˜Kšœ:˜:Kšžœ˜——Kšœ5˜5K˜——K˜K˜—š   œžœžœžœžœ˜QKšœK™KKšžœžœžœ+˜;šœ ˜ Kšœ˜Kš œžœžœžœžœžœ˜UKšœžœ˜—šžœ!ž˜'šžœ žœž˜Kšœ:˜:Kšžœ˜——Kšœ˜K˜K˜—š  œžœžœžœžœ˜XKšœ#˜#Kšœ˜K˜K˜—š  œžœ#˜4K™šœžœ˜Kšžœžœžœ˜ Kšžœžœžœ˜Kšžœžœ žœžœ˜Kšžœžœžœ˜#K™-Kšœ$˜$Kšœ&žœ˜-Kšœ@žœ˜GKšœ˜Kšœ˜K˜—Kšœ*˜*Kšœ¡,˜DKšœ5˜5K˜K˜—š   œžœžœžœžœ˜Pšœ¡*œ˜HKš žœ žœžœžœ žœžœ˜QKšœ˜—K˜"Kšœ˜K˜—š  œžœžœžœ žœžœ˜BKšžœžœžœ˜Kšœžœ˜Kšžœžœžœ˜(Kšžœžœžœ˜(Kšžœžœžœ˜(Kšžœžœ˜$K˜K˜—š œžœ žœžœ˜$Kšœžœ˜$K˜K˜—š œžœ˜Kšœ"˜"Kšœ˜—K˜š œ˜+Kšœ˜Kšœ˜K˜—š œ˜+šžœžœž˜Kšœžœ9˜CKšžœ˜—Kšœ˜K˜—š   œžœžœžœžœ˜0Kšžœ'˜-Kšœ˜K˜—š  œžœžœžœžœž œžœžœ˜aKšœžœžœ žœ ˜9Kšžœžœžœžœ˜>Kšœ˜—K˜Kšœžœ˜%šœ žœ˜"K˜—š œžœžœžœžœžœžœ žœžœžœ˜³Kšœ˜Kšœ žœžœ˜Kšœžœžœ˜Kšžœ žœžœ ˜šžœž˜Kšœ˜Kšœ'˜'Kšœ1˜1Kšžœžœ˜—Kšœp˜pšžœ žœžœ˜Kšœ™šžœžœ˜Kšœ"™"Kšœ,˜,šžœž˜šœžœ˜KšœE™EKšœ5˜5Kšœ žœ˜—Kšžœ˜—K˜—š žœžœžœ žœž˜:šœ*˜*Kšœ5™5Kšœ:˜:Kšœžœ˜#šžœ˜šžœ˜Kšœ ™ šœžœ.˜6Kšœžœžœ ˜!—KšœYžœ˜_Kšœ*˜*Kšœ1˜1Kšžœ˜K˜—šžœ˜Kšœ"™"Kšœ&˜&šœ˜Kšœ$žœžœžœ˜O—Kšœ˜šžœžœžœž˜)KšœC™CKšœ˜—Kšœ&˜&K˜——Kšœ ˜ Kšœ žœ˜K˜—Kšžœ˜—šžœžœž˜šœžœ˜ Kšœ_™_Kšœ˜š žœ žœžœžœžœž˜Ašžœ ˜Kšžœ˜Kšžœ+žœ˜5——K˜—šœ ˜ Kšœ˜—šœ ˜ Kšœ"˜"—Kšžœ˜—K˜—Kšœ˜K˜—š œžœžœ(žœžœ žœžœžœžœ˜›šœ™K™?K™'K™—Kšœžœžœ˜Kšœ žœžœ˜,Kšœžœ ˜Kšœ ˜ Kšžœžœžœ2˜Mšžœ#žœžœ˜2Kšœ)žœ˜0Kšœ˜—Kšœ˜Kšœ˜šžœ žœž˜˜)Kšœžœ˜Kšœžœ˜Kšœžœžœ˜šž˜Kšœ(˜(Kšžœ žœžœ˜4Kšœ?˜?š žœ)žœžœžœžœžœ˜jKšœz™z—Kšœ?˜?Kšžœ˜—˜KšžœžœC˜Pšœ.˜.K™ —Kšžœžœžœ˜;šžœ žœžœ˜šžœžœ˜šžœžœžœž˜$šœ+žœžœ ˜9Kšœ.™.—Kšžœ˜——Kšžœ˜K˜—šžœžœž˜šœ žœ˜Kšœ+™+KšœH˜Hšžœ ž˜šžœ˜Kšœ¡.˜Dš žœžœžœžœž˜BKšžœ<˜@Kšžœ˜#—Kšœ˜—šž˜Kšœ˜——K˜K˜Kšœ%žœ˜+šžœžœžœ˜Kšœžœ˜3Kšœžœ˜Kšœ˜—Kšœ žœ¡0˜@Kšœ?˜?Kšœžœ˜Kšœžœ˜Kšœ žœ˜K˜KšœI˜IKšœ ˜ K˜—šžœ˜ KšœI™IKšœ˜K˜——K˜Kšœ˜Kšœ?˜?Kšœ˜K˜—Kšžœžœ˜+K˜—Kšžœ˜—Kšœ˜K˜—š œ˜$Kšžœžœžœ˜šžœžœž˜Kšœ(˜(Kšžœ˜—K˜—K˜š  œžœžœžœžœžœžœ žœ˜`šœžœ˜%Kš œžœ žœžœžœ˜8—Kšœ˜K˜—š  œžœžœžœžœžœžœžœžœ žœ˜xKšœžœ˜š žœžœžœžœžœžœž˜@Kšœ<˜—K˜K˜—š œžœžœžœžœžœžœžœ žœ˜vKšœžœ˜š žœžœžœžœžœžœž˜@Kšœ.˜.Kšžœžœžœžœ˜"Kšžœ˜—K˜—K˜šœžœ žœžœ˜+K˜—š  œžœžœžœžœžœžœ žœ žœžœ žœžœ˜±Kšœžœ˜ Kšœ-žœžœ˜:Kšœ žœžœ˜K˜"Kšœ%˜%Kšœ9™9š žœžœž œžœž˜*šžœž˜KšœEžœ˜KKšžœ˜Kšžœžœ˜—Kšžœ˜—š žœžœž œžœž˜*šžœž˜Kšœžœ˜Kš œžœžœžœžœžœ˜FKšœžœ˜Kšžœ˜—Kšžœžœžœ˜%Kšžœ˜—Kšœ(˜(Kšžœžœžœžœ˜$šžœžœžœž˜,šžœ˜K˜WKšžœžœžœžœ˜$K˜——šžœžœžœ˜Kšœžœ˜Kšœ1˜1šžœžœ˜Kšœ*˜*Kšžœžœžœžœ˜:Kšœ˜—K˜—Kšžœžœžœ˜šžœžœ˜Kšœ˜Kšœ˜Kšžœ3žœžœ˜Sšžœžœžœ˜KšœV˜VKšžœžœžœžœ˜6K˜—Kšœ˜—šžœ žœžœ˜3Kšœ,˜,Kšœ¡˜4Kšžœžœžœžœ˜$šžœžœžœ˜K˜CKšžœžœžœžœ˜$K˜—šžœžœžœžœ˜$KšœB˜BKšžœžœžœžœ˜6K˜—K˜—K˜K˜—š  œžœžœžœžœžœ žœžœžœ˜nKšœžœ˜Kšœ žœ(˜8Kšœžœžœ˜#Kšœžœ#˜BKšœ@¡˜YKšœ=¡ ˜]šžœžœ˜Kšœ;˜;šžœ%˜,Kšœ>˜>—Kšœ˜—Kšžœžœžœ˜,Kšœ&˜&šœH˜HKšœ)˜)—Kšžœžœžœžœ˜6šžœ žœžœ˜3Kšœ1˜1KšœB˜BKšžœžœžœžœ˜6K˜—Kšžœ˜K˜K˜—š  œžœžœžœžœ˜KKšœ žœžœžœ˜3Kšžœžœžœ˜&˜Kšžœžœ žœ˜šžœžœžœ ž˜Kšžœžœ$žœ žœ˜]Kšžœžœžœ žœ˜S—Kšžœ$˜*K˜—Kšžœžœ˜K˜K˜—š œ œžœžœžœžœ˜:Kšžœžœ˜:K˜K˜—š œžœžœžœžœžœžœ˜PKšœžœžœžœ˜-šœžœ-˜LKšœžœ žœ˜—Kšžœžœžœžœžœžœžœ$˜NK˜K˜—š   œžœžœažœžœžœ˜¢Kšœ žœ&˜5Kšœžœ žœ˜$Kšœžœžœ˜Kšœžœžœ˜Kšžœžœžœ*˜9Kšžœžœžœ˜;Kšžœžœžœ˜;šžœžœ˜"Kšœžœ-˜7Kšžœžœžœ4žœ˜Pšžœž˜Kšœ;˜;Kšœ;˜;KšœC˜CKšžœžœ˜—Kšžœ ˜K˜—šœ˜šžœ˜Kšžœ&žœ˜4Kšœ2žœ˜>K˜—šžœž˜šœK˜KKšœP˜P—K˜NKšžœžœ˜—Kšžœžœžœžœ˜FK˜—Kšœ=˜=Kšžœ žœžœ˜K˜K™—™ššœ™Kšœ™Kšœ™Kšœ™—šœ™Kšœ#™#—šœ™Kšœ)™)Kšœ"™"Kšœ*™*—šœ™Kšœ-™-Kšœ&™&Kšœ.™.—šœ ™ Kšœ™Kšœ™Kšœ ™ —šœ™Kšœ™—šœ™Kšœ"™"K™—šœ ™ Kšœ™—šœ ™ Kšœ™K™—™Kšœ™Kšœ™—K™—š  œžœžœžœ˜:šœžœ+˜6Kšœ˜Kšœžœ˜Kšžœžœžœ+˜;Kšœ/˜/šœ˜Kšžœžœ&˜3Kšœžœ ˜Kšœ3˜3K˜K˜Kšœžœ-¡˜Išžœžœž˜Kšœžœ˜#šœžœžœžœ˜EKšœB˜B—Kšžœ"˜)—Kšœ˜Kšœžœ˜Kšœ%žœ˜+Kšœ žœ¡!˜2Kšœ*žœ˜/Kšœ˜K˜Kšœ/¡˜FK˜K˜K˜—Kšœ"˜"K˜—Kšžœ žœžœ,˜@Kšœ˜K˜—š  œžœžœ˜-K˜Kšœ˜K˜—š   œžœžœžœžœ˜IKšœ/˜/šœ˜Kšžœžœ&˜3Kšœ˜Kšœ˜Kšœ˜—Kšœ"˜"Kšœ˜K˜—š  œžœžœ˜+Kšœ˜Kšœ˜K˜—š œžœžœžœ˜KKšœ7˜7šœžœžœ&˜5K˜!K˜K˜—Kšœ"˜"K˜K˜—š œžœžœ˜3Kšœ!˜!Kšœ˜K˜—š  œžœžœžœžœ žœžœ˜SKšœžœžœ˜>šœ1˜1Kšœžœžœ žœ˜7Kšœ(˜(—Kšœ˜K˜—š œžœžœ˜*Kšœ*žœ žœ˜=Kšœ˜K˜—š  œžœžœ žœžœ/žœžœ˜}Kšœw˜wKšœ˜K˜—š œžœžœ˜*Kšœžœ˜/Kšœ˜K˜—š  œžœžœžœžœžœ˜cKšœQ˜QKšœ˜K˜—š œžœžœ/žœ˜Tšœžœ0˜GKšœ(˜(—Kšœ˜—K˜š œžœžœžœžœ žœžœžœ˜tšœ1˜1Kšœžœžœ žœ˜6—Kšœ˜K˜—š  œžœžœ˜.Kšœ.žœ˜3Kšœ˜K˜—š œžœžœ žœžœžœžœ˜eKšœL˜LKšœ˜K˜—š  œžœžœ˜.Kšœžœ˜3Kšœ˜K˜—š  œžœžœžœžœžœ˜gKšœO˜OKšœ˜K˜—š œžœžœ˜6Kšœ$žœ˜)Kšœ˜K˜—šœžœ¡"˜MKšœžœ ˜ Kšœ%˜%Kšœžœ ˜Kšœ žœ˜Kšœžœ˜Kšžœžœžœžœ˜šœ7˜7Kšœ$™$—Kšœžœ,˜9Kšœ˜š žœžœžœ$žœžœ˜?Kšœ:˜:Kšžœ˜Kšœ˜—K˜KšœP˜PK˜K˜—š œžœ!˜9šžœ žœž˜šœ)˜)Kšœžœ ˜Kšœ žœ˜Kšœ žœ˜Kšœžœ ˜šœ:˜:Kšœ$™$—Kšœžœ,˜9Kšœ˜š žœžœžœ$žœžœ˜AKšœ:˜:Kšžœ˜ —K˜-Kšœžœžœ&žœ ˜OKšœvžœ˜}K˜—Kšžœ˜—Kšžœ žœ˜Kšœ˜K˜—š œžœžœ˜2Kšœ.˜.Kšœ˜K˜—š œžœžœ˜2Kšœ.˜.Kšœ˜K˜—š œžœžœ˜:Kšœ1˜1Kšœ˜K˜—š   œžœžœžœžœžœ˜IKšœžœ&˜0Kšœ žœžœ˜+Kšœ!žœžœ žœ˜SKšžœC¡˜YKšžœ žœ˜;K˜K˜—š   œžœžœžœžœžœ˜Kšœ˜K˜—šœ žœ¡˜CKšœžœ&˜/Kš œ žœžœžœžœ˜(Kšžœžœžœ˜6Kšœžœ˜.Kšžœ žœžœžœ˜K˜Kšœ,žœžœžœ˜ZK˜K˜—š   œžœžœžœžœ˜Cšœžœ+˜6Kšœžœžœ˜Kšœ žœ˜Kšœ žœ˜Kšžœ žœžœ/˜CKšžœžœžœ˜;K˜+Kšžœ žœžœžœ˜Kšžœžœžœ˜2Kšžœžœ¡ ˜DK˜%Kšœ-žœ¡˜Ošœ˜Kšœžœ6˜>—šžœžœ˜Kšœ™Kšœžœ˜ K˜Kšœ5˜5Kšœ žœ¡!˜1Kšœ+žœ˜0Kšœ ˜ Kšœ#˜#Kšœ˜—K˜—Kšœ)˜)Kšœ˜K˜—š  œžœ žœ>žœ˜fšœ žœ˜šžœ žœž˜šœ)˜)Kšœ)˜)Kšœ žœ˜1Kšœ˜K˜—Kšž˜—K˜—KšœD˜DK˜K˜—š  œžœžœ˜+Kšœ&žœ˜+Kšœ˜K˜—š œžœžœžœ˜;Kšœ&˜&Kšžœ#˜)K˜K˜—š œžœCžœ˜dšžœ ž˜Kšžœ)˜-šžœ˜Kšœžœ˜&Kšœžœ˜šžœ˜ Kšžœ˜ šžœ˜Kšœs˜sKšžœžœžœ žœ2˜LK˜——K˜——K˜K˜—š œžœžœ/žœ˜UKšœ]˜]K˜K˜—š œžœžœ˜7Kšœ3˜3K˜K˜—K˜šœ˜Kšœ=˜=—šœ!˜!Kšœ=˜=—šœ#˜#Kšœ=˜=—šœ"˜"Kšœ=˜=—K˜Kšžœ˜K˜K˜—…—‡p½†