DIRECTORY LongString USING [AppendChar, AppendString, AppendDecimal], Rope USING [Fetch, ROPE, Size], RopeEdit USING [AlphaNumericChar, BlankChar, Concat, Substr], RopeReader USING [Create, Get, GetIndex, Backwards, ReadOffEnd, Ref, SetPosition], TextEdit USING [DeleteText, FetchChar, FetchLooks, InsertChar, InsertRope, Offset, Ref, RefTextNode, ReplaceByChar, InsertString, Size], TextLooks USING [Look, Looks, noLooks], TextNode USING [Backward, FirstChild, LastLocWithin, Location, NarrowToTextNode, NodeItself, Offset, Parent, Ref, RefTextNode, StepForward, StepBackward, TypeName], TEditDocument USING [BeforeAfter, Selection, SelectionPoint], TEditInput USING [CloseEvent, currentEvent], TEditInputOps, TEditOps, TEditRefresh USING [ScrollToEndOfSel], TEditSelection USING [CaretVisible, Copy, Deselect, InsertionPoint, LockSel, MakePointSelection, MakeSelection, pSel, SetSelLooks, UnlockSel], Time USING [Current, Unpack, Unpacked], TreeFind USING [Finder, CreateFromRope, Try, TryBackwards], ViewerClasses USING [Viewer], ViewerTools USING [SetSelection]; TEditMiscOpsImpl: CEDAR PROGRAM IMPORTS LongString, Rope, RopeEdit, RopeReader, TextEdit, TextNode, TEditInput, TEditInputOps, TEditOps, TEditRefresh, TEditSelection, Time, TreeFind, ViewerTools EXPORTS TEditInputOps = BEGIN OPEN TEditDocument, TEditSelection, TEditOps, TEditInputOps; InsertChar: PUBLIC PROC [char: CHARACTER] = { DoInsertChar: PROC [root: TextEdit.Ref, tSel: Selection] = { pos: TextNode.Location; looks: TextLooks.Looks _ tSel.looks; IF tSel.pendingDelete THEN { DoPendingDelete[]; TEditSelection.Copy[source: pSel, dest: tSel] }; pos _ InsertionPoint[pSel]; -- need to get insertion point after pending delete Deselect[primary]; [] _ TextEdit.InsertChar[root: root, dest: TextNode.NarrowToTextNode[pos.node], char: char, destLoc: pos.where, inherit: FALSE, looks: looks, event: TEditInput.currentEvent]; pos.where _ pos.where+1; MakePointSelection[tSel, pos]; IF CaretVisible[] THEN TEditRefresh.ScrollToEndOfSel[tSel.viewer, TRUE] }; CallWithLocks[DoInsertChar] }; InsertRope: PUBLIC PROC [rope: Rope.ROPE] = { DoInsertRope: PROC [root: TextEdit.Ref, tSel: Selection] = { pos: TextNode.Location; len: TextNode.Offset _ Rope.Size[rope]; looks: TextLooks.Looks; IF tSel.pendingDelete THEN { DoPendingDelete[]; TEditSelection.Copy[source: pSel, dest: tSel] }; pos _ InsertionPoint[pSel]; -- need to get insertion point after pending delete looks _ tSel.looks; Deselect[primary]; [] _ TextEdit.InsertRope[root: root, dest: TextNode.NarrowToTextNode[pos.node], rope: rope, destLoc: pos.where, inherit: FALSE, looks: looks, event: TEditInput.currentEvent]; pos.where _ pos.where+len; MakePointSelection[tSel, pos]; IF CaretVisible[] THEN TEditRefresh.ScrollToEndOfSel[tSel.viewer, TRUE] }; CallWithLocks[DoInsertRope] }; InsertLineBreak: PUBLIC PROC = { -- copy leading blanks from previous line DoInsertLineBreak: PROC [root: TextEdit.Ref, tSel: Selection] = { pos: TextNode.Location; node: TextNode.RefTextNode; start, end: TextNode.Offset; rope: Rope.ROPE; IF tSel.pendingDelete THEN { DoPendingDelete[]; TEditSelection.Copy[source: pSel, dest: tSel] }; pos _ InsertionPoint[pSel]; -- need to get insertion point after pending delete IF (node _ TextNode.NarrowToTextNode[pos.node]) = NIL THEN { EditFailed[]; RETURN }; rope _ node.rope; start _ MAX[0, pos.where]; start _ MIN[start, Rope.Size[rope]]; WHILE start > 0 AND Rope.Fetch[rope,start-1] # 15C DO start _ start-1; ENDLOOP; end _ start; WHILE end < pos.where AND RopeEdit.BlankChar[Rope.Fetch[rope,end]] DO end _ end+1; ENDLOOP; InsertRope[RopeEdit.Concat["\n",RopeEdit.Substr[rope,start,end-start]]] }; CallWithLocks[DoInsertLineBreak] }; DeleteNextChar: PUBLIC PROC [count: INT _ 1] = { DoDeleteNextChar: PROC [root: TextEdit.Ref, tSel: Selection] = { flush: TextNode.Location _ InsertionPoint[tSel]; node: TextNode.RefTextNode; IF (node _ TextNode.NarrowToTextNode[flush.node]) = NIL THEN GOTO Bad; IF flush.where=TextNode.NodeItself THEN GOTO Bad; IF (count _ MIN[count,TextEdit.Size[node]-flush.where]) <= 0 THEN GOTO Bad; Deselect[primary]; TextEdit.DeleteText[root, node, flush.where, count, TEditInput.currentEvent]; MakePointSelection[tSel,flush]; TEditRefresh.ScrollToEndOfSel[tSel.viewer, TRUE]; EXITS Bad => EditFailed[] }; IF count > 0 THEN CallWithLocks[DoDeleteNextChar] }; GoToNextChar: PUBLIC PROC [count: INT _ 1] = { DoGoToNextChar: PROC [root: TextEdit.Ref, tSel: Selection] = { loc: TextNode.Location _ InsertionPoint[tSel]; node: TextNode.RefTextNode; IF (node _ TextNode.NarrowToTextNode[loc.node]) = NIL OR loc.where=TextNode.NodeItself OR (count _ MIN[count,TextEdit.Size[node]-loc.where]) <= 0 THEN { -- try next node GoToNextNode; RETURN }; MakePointSelection[tSel,[node,loc.where+count]]; TEditRefresh.ScrollToEndOfSel[tSel.viewer, TRUE] }; IF count > 0 THEN CallWithLocks[DoGoToNextChar, read] }; GoToPreviousChar: PUBLIC PROC [count: INT _ 1] = { DoGoToPreviousChar: PROC [root: TextEdit.Ref, tSel: Selection] = { loc: TextNode.Location _ InsertionPoint[tSel]; node: TextNode.RefTextNode; IF (node _ TextNode.NarrowToTextNode[loc.node]) = NIL OR loc.where=TextNode.NodeItself OR loc.where < count THEN { GoToPreviousNode; RETURN }; -- try previous node MakePointSelection[tSel,[node,loc.where-count]]; TEditRefresh.ScrollToEndOfSel[tSel.viewer, TRUE] }; IF count > 0 THEN CallWithLocks[DoGoToPreviousChar, read] }; FindNextWord: PUBLIC PROC [node: TextNode.RefTextNode, start: TextNode.Offset] RETURNS [nChars: CARDINAL] = { offset: TextNode.Offset _ start; size: TextNode.Offset _ TextEdit.Size[node]; nChars _ 1; WHILE offset EditFailed[] }; IF count > 0 THEN CallWithLocks[DoDeleteNextWord] }; GoToNextWord: PUBLIC PROC [count: INT _ 1] = { DoGoToNextWord: PROC [root: TextEdit.Ref, tSel: Selection] = { pos: TextNode.Location _ InsertionPoint[tSel]; node: TextNode.RefTextNode; size, next: TextEdit.Offset; IF (node _ TextNode.NarrowToTextNode[pos.node])=NIL OR (next _ pos.where)=TextNode.NodeItself THEN { -- try next node GoToNextNode; RETURN }; size _ TextEdit.Size[node]; FOR garbage:INT IN [0..count) DO IF next >= size THEN { GoToNextNode; RETURN }; next _ next+FindNextWord[node,next]; ENDLOOP; MakePointSelection[tSel,[node,next]]; TEditRefresh.ScrollToEndOfSel[tSel.viewer, TRUE] }; IF count > 0 THEN CallWithLocks[DoGoToNextWord, read] }; GoToNextNode: PUBLIC PROC [count: INT _ 1] = { DoGoToNextNode: PROC [root: TextEdit.Ref, tSel: Selection] = { pos: TextNode.Location _ InsertionPoint[tSel]; node: TextNode.Ref _ pos.node; FOR garbage:INT IN [0..count) DO IF (node _ TextNode.StepForward[node])=NIL THEN { EditFailed[]; RETURN }; ENDLOOP; MakePointSelection[tSel,[node,0]]; TEditRefresh.ScrollToEndOfSel[tSel.viewer, TRUE] }; IF count > 0 THEN CallWithLocks[DoGoToNextNode, read] }; GoToPreviousNode: PUBLIC PROC [count: INT _ 1] = { DoGoToPreviousNode: PROC [root: TextEdit.Ref, tSel: Selection] = { text: TextNode.RefTextNode; pos: TextNode.Location _ InsertionPoint[tSel]; node: TextNode.Ref _ pos.node; FOR garbage:INT IN [0..count) DO IF (node _ TextNode.StepBackward[node])=NIL OR TextNode.Parent[node]=NIL THEN GOTO Bad; ENDLOOP; IF (text _ TextNode.NarrowToTextNode[node])=NIL THEN GOTO Bad; MakePointSelection[tSel,[text,TextEdit.Size[text]]]; TEditRefresh.ScrollToEndOfSel[tSel.viewer, TRUE]; EXITS Bad => EditFailed[] }; IF count > 0 THEN CallWithLocks[DoGoToPreviousNode, read] }; InsertTime: PUBLIC PROC = { dateLen: TextEdit.Offset; TimeString: PROC RETURNS [time: REF TEXT] = TRUSTED BEGIN OPEN LongString; s: LONG STRING; -- for convenience; now: Time.Unpacked = Time.Unpack[Time.Current[]]; time _ NEW[TEXT[30]]; s _ LOOPHOLE[time]; AppendString[s, SELECT now.month FROM 0 => "January"L, 1 => "February"L, 2 => "March"L, 3 => "April"L, 4 => "May"L, 5 => "June"L, 6 => "July"L, 7 => "August"L, 8 => "September"L, 9 => "October"L, 10 => "November"L, ENDCASE => "December"L]; AppendChar[s, ' ]; AppendDecimal[s, now.day]; AppendString[s , ", "]; AppendDecimal[s, now.year]; dateLen _ s.length; -- remember length of date for selection AppendChar[s, ' ]; AppendDecimal[s, ((now.hour+11) MOD 12)+1]; AppendChar[s, ':]; AppendDecimal[s, now.minute/10]; AppendDecimal[s, now.minute MOD 10]; AppendString[s, IF now.hour<12 THEN " am" ELSE " pm"]; END; DoInsertTime: PROC [root: TextEdit.Ref, tSel: Selection] = { resLen: TextEdit.Offset; caret: TextNode.Location; dest: TextNode.RefTextNode; looks: TextLooks.Looks; looks _ pSel.looks; IF pSel.pendingDelete THEN DoPendingDelete[]; caret _ InsertionPoint[pSel]; IF (dest _ TextNode.NarrowToTextNode[caret.node])=NIL THEN GOTO Bad; Deselect[primary]; [----, resLen] _ TextEdit.InsertString[root: root, dest: dest, string: TimeString[], destLoc: caret.where, inherit: FALSE, looks: looks, event: TEditInput.currentEvent]; tSel.end.pos.node _ tSel.start.pos.node _ caret.node; tSel.end.pos.where _ caret.where+resLen-1; tSel.start.pos.where _ caret.where+dateLen; tSel.insertion _ after; tSel.granularity _ char; tSel.pendingDelete _ FALSE; MakeSelection[selection: primary, new: tSel]; EXITS Bad => EditFailed[] }; CallWithLocks[DoInsertTime] }; InsertBrackets: PUBLIC PROC [left, right: CHAR] = { DoInsertBrackets: PROC [root: TextEdit.Ref, tSel: Selection] = { leftEnd, rightEnd: TextNode.Location; leftNode, rightNode: TextNode.RefTextNode; l, r: TextNode.Offset; leftEnd _ tSel.start.pos; rightEnd _ tSel.end.pos; IF (leftNode _ TextNode.NarrowToTextNode[leftEnd.node])=NIL THEN GOTO Bad; IF (rightNode _ TextNode.NarrowToTextNode[rightEnd.node])=NIL THEN GOTO Bad; IF (r _ rightEnd.where) = TextNode.NodeItself THEN r _ TextEdit.Size[rightNode] ELSE IF tSel.granularity # point THEN r _ r+1; IF (l _ leftEnd.where) = TextNode.NodeItself THEN l _ 0; Deselect[primary]; [----, ----] _ TextEdit.InsertChar[ root: root, dest: rightNode, char: right, destLoc: r, inherit: FALSE, looks: tSel.looks, event: TEditInput.currentEvent]; [----, ----] _ TextEdit.InsertChar[ root: root, dest: leftNode, char: left, destLoc: l, inherit: FALSE, looks: tSel.looks, event: TEditInput.currentEvent]; tSel.start.pos.where _ l+1; IF tSel.granularity = point THEN tSel.end.pos.where _ l+1 ELSE { tSel.granularity _ char; IF leftNode=rightNode THEN tSel.end.pos.where _ r}; tSel.pendingDelete _ FALSE; MakeSelection[selection: primary, new: tSel]; EXITS Bad => EditFailed[] }; CallWithLocks[DoInsertBrackets] }; End: ERROR = CODE; -- private; for use in SelectMatchingBrackets SelectMatchingBrackets: PUBLIC PROC [left, right: CHAR] = { IF ~DoSelectMatchingBrackets[left, right] THEN EditFailed["No match."] }; DoSelectMatchingBrackets: PUBLIC PROC [left, right: CHAR] RETURNS [found: BOOL] = { rdr: RopeReader.Ref _ RopeReader.Create[]; ref, parent: TextNode.Ref; node: TextNode.RefTextNode; GetPreviousNode: PROC RETURNS [n: TextNode.RefTextNode] = { DO -- search for previous text node [ref,parent,] _ TextNode.Backward[ref,parent]; IF ref=NIL THEN ERROR End; IF (n _ TextNode.NarrowToTextNode[ref]) # NIL THEN RETURN [n]; ENDLOOP }; GetLeftChar: PROC RETURNS [CHAR] = { RETURN [RopeReader.Backwards[rdr ! RopeReader.ReadOffEnd => { node _ GetPreviousNode[]; RopeReader.SetPosition[rdr, node.rope, Rope.Size[node.rope]]; RETRY }]] }; GetNextNode: PROC RETURNS [n: TextNode.RefTextNode] = { DO -- search for next text node IF (ref _ TextNode.StepForward[ref])=NIL THEN ERROR End; IF (n _ TextNode.NarrowToTextNode[ref]) # NIL THEN RETURN [n]; ENDLOOP }; GetRightChar: PROC RETURNS [CHAR] = { RETURN [RopeReader.Get[rdr ! RopeReader.ReadOffEnd => { node _ GetNextNode[]; RopeReader.SetPosition[rdr, node.rope]; RETRY }]] }; DoSelect: PROC [root: TextEdit.Ref, tSel: Selection] = { leftEnd, rightEnd: TextNode.Location; nest: CARDINAL _ 0; loc: TextNode.Offset; leftEnd _ tSel.start.pos; rightEnd _ tSel.end.pos; ref _ leftEnd.node; IF (node _ TextNode.NarrowToTextNode[ref])=NIL THEN { IF (node _ GetPreviousNode[])=NIL THEN GOTO NoMatch; loc _ Rope.Size[node.rope] } ELSE IF (loc _ leftEnd.where) = TextNode.NodeItself THEN loc _ 0; RopeReader.SetPosition[rdr, node.rope, loc]; DO -- left end SELECT GetLeftChar[ ! End => GOTO NoMatch] FROM left => IF nest=0 THEN EXIT ELSE nest _ nest-1; right => nest _ nest+1; ENDCASE; ENDLOOP; leftEnd.node _ node; leftEnd.where _ RopeReader.GetIndex[rdr]; ref _ rightEnd.node; IF (node _ TextNode.NarrowToTextNode[ref])=NIL THEN { IF (node _ GetNextNode[])=NIL THEN GOTO NoMatch; loc _ 0 } ELSE IF (loc _ rightEnd.where) = TextNode.NodeItself THEN loc _ Rope.Size[node.rope] ELSE IF pSel.granularity # point THEN loc _ loc+1; RopeReader.SetPosition[rdr, node.rope, loc]; DO -- right end SELECT GetRightChar[ ! End => GOTO NoMatch] FROM right => IF nest=0 THEN EXIT ELSE nest _ nest-1; left => nest _ nest+1; ENDCASE; ENDLOOP; rightEnd.node _ node; rightEnd.where _ RopeReader.GetIndex[rdr]-1; tSel.start.pos _ leftEnd; tSel.end.pos _ rightEnd; tSel.granularity _ char; SetSelLooks[tSel]; MakeSelection[selection: primary, new: tSel]; found _ TRUE; EXITS NoMatch => found _ FALSE }; CallWithLocks[DoSelect, read] }; NextViewer: PUBLIC PROC [forward: BOOLEAN] = BEGIN IF ~DoNextViewer[forward] THEN EditFailed["No next viewer."] END; DoNextViewer: PUBLIC PROC [forward: BOOLEAN] RETURNS [found: BOOL] = BEGIN OPEN ViewerClasses; Enumerate: PROC [enum: PROC [Viewer]] = BEGIN FOR v: Viewer _ pSel.viewer.parent.child, v.sibling UNTIL v=NIL DO enum[v]; ENDLOOP; END; thisViewer: Viewer = pSel.viewer; nextViewer: Viewer _ NIL; ConvergeForward: PROC [v: Viewer] = BEGIN IF v.class.flavor=$Text AND (v.cy > thisViewer.cy OR (v.cy = thisViewer.cy AND v.cx > thisViewer.cx)) THEN BEGIN IF nextViewer=NIL OR v.cy < nextViewer.cy THEN {nextViewer _ v; RETURN}; IF v.cy > nextViewer.cy THEN RETURN; IF (v.cy > thisViewer.cy OR v.cx > thisViewer.cx) AND v.cx < nextViewer.cx THEN nextViewer _ v; END; END; ConvergeBackward: PROC [v: Viewer] = BEGIN IF v.class.flavor=$Text AND (v.cy < thisViewer.cy OR (v.cy = thisViewer.cy AND v.cx < thisViewer.cx)) THEN BEGIN IF nextViewer=NIL OR v.cy > nextViewer.cy THEN {nextViewer _ v; RETURN}; IF v.cy < nextViewer.cy THEN RETURN; IF (v.cy < thisViewer.cy OR v.cx < thisViewer.cx) AND v.cx > nextViewer.cx THEN nextViewer _ v; END; END; LockSel[primary, "DoNextViewer"]; { ENABLE UNWIND => UnlockSel[primary]; IF pSel.viewer=NIL OR pSel.viewer.parent=NIL THEN { UnlockSel[primary]; EditFailed[]; RETURN [FALSE] }; Enumerate[IF forward THEN ConvergeForward ELSE ConvergeBackward]; IF nextViewer # NIL THEN ViewerTools.SetSelection[nextViewer, NIL]; }; UnlockSel[primary]; RETURN [nextViewer # NIL]; END; FindPlaceholders: PUBLIC PROCEDURE [next: BOOLEAN] = { found, wenttoend: BOOL; [found, wenttoend] _ DoFindPlaceholders[next, TRUE]; IF ~found AND ~wenttoend THEN NextViewer[next] }; DoFindPlaceholders: PUBLIC PROCEDURE [next, gotoend: BOOL, startBoundaryNode, endBoundaryNode: TextNode.Ref _ NIL, startBoundaryOffset: TextNode.Offset _ 0, endBoundaryOffset: TextNode.Offset _ LAST[TextNode.Offset]] RETURNS [found, wenttoend: BOOL] = { DoFind: PROC [root: TextEdit.Ref, tSel: Selection] = { finder: TreeFind.Finder _ TreeFind.CreateFromRope[IF next THEN "" ELSE ""]; from: TextNode.Location; where: TextNode.RefTextNode; at, atEnd, start: TextNode.Offset; Failed: PROC = { IF gotoend THEN { loc: TextNode.Location = IF next THEN TextNode.LastLocWithin[root] ELSE [TextNode.FirstChild[root],0]; IF loc # from OR tSel.granularity # point THEN { wenttoend _ TRUE; RememberCurrentPosition[tSel.viewer]; MakePointSelection[tSel, loc]; TEditRefresh.ScrollToEndOfSel[tSel.viewer, FALSE] }}; }; from _ InsertionPoint[tSel]; start _ from.where; IF next AND tSel.insertion=before AND tSel.granularity#point THEN start _ start+1 ELSE IF ~next AND tSel.insertion=after THEN start _ MAX[start-1,0]; [found,where,at,atEnd,,] _ IF next THEN TreeFind.Try[finder: finder, first: from.node, start: start, last: endBoundaryNode, lastLen: endBoundaryOffset] ELSE TreeFind.TryBackwards[finder: finder, first: from.node, len: start, last: startBoundaryNode, lastStart: startBoundaryOffset]; wenttoend _ FALSE; IF ~found THEN { Failed[]; RETURN }; MakePointSelection[tSel, [where,IF next THEN at+1 ELSE MAX[at,0]]]; IF ~DoSelectMatchingBrackets[','] THEN { Failed[]; RETURN }; TEditSelection.Copy[source: pSel, dest: tSel]; tSel.insertion _ before; tSel.pendingDelete _ TRUE; RememberCurrentPosition[tSel.viewer]; tSel.looks _ TextEdit.FetchLooks[ -- take looks from first char after the  TextNode.NarrowToTextNode[tSel.start.pos.node], tSel.start.pos.where+1]; MakeSelection[tSel, primary]; TEditInput.CloseEvent[]; TEditRefresh.ScrollToEndOfSel[tSel.viewer, FALSE]; }; CallWithLocks[DoFind, read] }; END. -- TEditMiscOpsImpl.mesa Edited by Paxton on June 6, 1983 4:09 pm Last Edited by: Maxwell, January 6, 1983 11:33 am -- insert left char at start of selection, right char after selection -- extend selection until includes matching left and right brackets Κ΄˜JšΟcA™AJšΟk1™1Jšž ˜ ˜Jšœ žœ+˜;Jšœžœ žœ˜Jšœ žœ/˜=Jšœ žœB˜RJšœ žœz˜ˆJšœ žœ˜'Jšœ žœ–˜€Jšœžœ*˜=Jšœ žœ˜,J˜J˜ Jšœ žœ˜&Jšœžœz˜ŽJšœžœ˜'Jšœ žœ-˜;Jšœžœ ˜Jšœ žœ˜!J˜—Jšœž ˜J˜Jšžœ›˜’Jšžœž˜Jšžœ8˜Jšœ.˜.J˜šžœ0žœž˜8Jšœž˜ Jšœ žœ,žœ˜OJšœžœ˜—Jšœ0˜0Jšœ+žœ˜3—Jšžœ žœ'˜8J˜—šŸœžœžœ žœ ˜2šŸœžœ*˜BJšœ.˜.J˜šžœ0žœž˜8Jšœžœ˜3Jšžœžœ˜7—Jšœ0˜0Jšœ+žœ˜3—Jšžœ žœ+˜ž˜UJ˜J˜Jšžœ˜—šžœ žœ=ž˜TJ˜J˜Jšžœ˜—Jšœ#˜8J˜J˜—šŸœžœžœ žœ ˜0šŸœžœ*˜@Jšœ.˜.J˜J˜%Jšžœ+žœžœ˜;Jšžœ.žœžœžœ˜BJ˜ Jš žœ žœžœ žœ&žœ˜NJ˜J˜JšœH˜HJšœ˜Jšœ+žœ˜1Jšžœ˜—Jšžœ žœ#˜4J˜—šŸ œžœžœ žœ ˜.šŸœžœ*˜>Jšœ.˜.J˜J˜šžœ.žœž˜6Jšœ'žœ˜>Jšœžœ˜—J˜šžœ žœžœ ž˜ Jšžœžœžœ˜.J˜$Jšžœ˜—Jšœ%˜%Jšœ+žœ˜3—Jšžœ žœ'˜8J˜—šŸ œžœžœ žœ ˜.šŸœžœ*˜>Jšœ.˜.J˜šžœ žœžœ ž˜ Jšžœ%žœžœžœ˜IJšžœ˜—Jšœ"˜"Jšœ+žœ˜3—Jšžœ žœ'˜8J˜—šŸœžœžœ žœ ˜2šŸœžœ*˜BJ˜Jšœ.˜.J˜šžœ žœžœ ž˜ šžœ&žœž˜.Jšœžœžœžœ˜(—Jšžœ˜—Jšžœ*žœžœžœ˜>Jšœ4˜4Jšœ+žœ˜1Jšžœ˜—Jšžœ žœ+˜Jšžœ˜ J˜—šŸ œžœžœžœ˜$šžœ7˜=J˜J˜=Jšžœ˜ J˜——šŸ œžœžœ˜7Jšžœ˜Jšžœ#žœžœžœ˜8Jšžœ(žœžœžœ˜>Jšžœ˜ J˜—šŸ œžœžœžœ˜%šžœ1˜7J˜J˜'Jšžœ˜ J˜——šŸœžœ*˜8J˜%Jšœžœ˜J˜J˜Jšœ˜Jšœ˜J˜J˜šžœ)žœžœ˜5Jšžœžœžœžœ ˜4J˜—Jšžœžœ-žœ ˜AJ˜,šžœ ˜šžœžœ ž˜/Jš œžœžœžœžœ˜/J˜Jšžœ˜—Jšžœ˜—J˜J˜)J˜J˜šžœ)žœžœ˜5Jšžœžœžœžœ ˜0J˜ —šžœžœ.žœ˜TJšžœžœžœ ˜2—J˜,šžœ ˜šžœžœ ž˜0Jš œ žœžœžœžœ˜0J˜Jšžœ˜—Jšžœ˜—J˜J˜,J˜J˜J˜J˜J˜J˜-Jšœžœ˜ Jšžœžœ˜!—J˜Jšœ ˜ J˜—š Ÿ œžœžœ žœž˜2Jšžœžœžœ˜AJ˜—š Ÿ œžœžœ žœžœ žœž˜JJšžœ˜šŸ œžœžœ ž˜-šžœ1žœžœž˜BJ˜Jšžœ˜—Jšžœ˜—J˜!Jšœžœ˜šŸœžœž˜)Jšžœžœ˜1šžœžœžœž˜>Jš žœ žœžœžœžœ˜HJšžœžœžœ˜$šžœžœžœž˜OJ˜—Jšžœ˜—Jšžœ˜—šŸœžœž˜*Jšžœžœ˜1šžœžœžœž˜>Jš žœ žœžœžœžœ˜HJšžœžœžœ˜$šžœžœžœž˜OJ˜—Jšžœ˜—Jšžœ˜—Jšœ!˜!Jšœžœžœ˜&š žœ žœžœžœžœ˜3Jšœ"žœžœ˜3—Jšœ žœ žœžœ˜AJšžœžœžœ&žœ˜CJšœ˜Jšžœžœ˜Jšžœ˜—J˜šŸœžœž œžœ˜6Jšœžœ˜Jšœ.žœ˜4šžœžœ žœ˜1J˜——šŸœžœž œžœ˜:Jšœ3žœ˜7Iprocšœ)˜)Kšœ%žœ˜;Jšžœžœ˜$šŸœžœ*˜6Jšœ2žœžœžœ˜MJ˜J˜J˜"šŸœžœ˜šžœ žœ˜šœžœžœ˜BJšžœ˜#—šžœ žœžœ˜0Jšœ žœ˜Jšœ%˜%J˜Jšœ+žœ˜5——Jšœ˜—Jšœ˜J˜Jšžœžœžœžœ˜QJš žœžœžœžœ žœ ˜Cšœžœž˜'šœ<˜J˜.J˜Jšœžœ˜Jšœ%˜%šœ")˜KJšœH˜H—J˜J˜Jšœ+žœ˜2Jšœ˜—J˜J˜—Jšžœ˜J˜—…—DΘW€