DIRECTORY Atom, CDBasics, CDTexts, CDTextsBackdoor, CDEvents, CDLayers, CDPrivate, CDProperties, CD, CDIO, FS, Imager, ImagerFont, ImagerTransformation, IO, LRUCache, NodeStyle, NodeStyleFont, Real, Rope, RuntimeError USING [UNCAUGHT], SymTab, TerminalIO, TokenIO, VFonts; CDTextsImpl: CEDAR MONITOR IMPORTS Atom, CD, CDBasics, CDIO, CDEvents, CDLayers, CDPrivate, CDProperties, CDTexts, FS, Imager, ImagerFont, ImagerTransformation, IO, LRUCache, NodeStyleFont, Real, Rope, RuntimeError, SymTab, TerminalIO, TokenIO, VFonts EXPORTS CDTexts, CDTextsBackdoor = BEGIN TextSpecific: TYPE = CDTexts.TextSpecific; TextRec: TYPE = CDTexts.TextRec; FontRec: TYPE = CDTexts.FontRec; CDFont: TYPE = CDTexts.CDFont; convertClass: PUBLIC CD.ObjectClass _ CD.RegisterObjectClass[$Text, [ internalRead: ConvertRead ]]; rigidTextClass: PUBLIC CD.ObjectClass _ CD.RegisterObjectClass[$RigidText, [ drawMe: FixDraw, quickDrawMe: FixDraw, internalRead: Read, internalWrite: Write, newLayer: ChangeLayer, describe: Describe ]]; flipTextClass: PUBLIC CD.ObjectClass _ CD.RegisterObjectClass[$FlipText, [ drawMe: FlipDraw, quickDrawMe: FlipDraw, internalRead: Read, internalWrite: Write, newLayer: ChangeLayer, describe: Describe ]]; textClass: PUBLIC CD.ObjectClass _ flipTextClass; lruQueue: LRUCache.Handle _ LRUCache.Create[127, CDPrivate.Hash, Equal]; free: CD.Object _ NIL; GiveOb: ENTRY PROC [] RETURNS [ob: CD.Object] = { ob _ free; free _ NIL; IF ob=NIL THEN ob _ NEW[CD.ObjectRep_[specific: NEW[TextRec]]]; }; Equal: PROC[x, y: REF] RETURNS [BOOL] = { EqualSpec: PROC[x, y: CD.Object] RETURNS [BOOL] = { tp1: TextSpecific = NARROW[x.specific]; tp2: TextSpecific = NARROW[y.specific]; RETURN [ Rope.Equal[tp1.text, tp2.text, TRUE] AND Rope.Equal[tp1.cdFont.supposedKey, tp2.cdFont.supposedKey, TRUE] ] }; ob1: CD.Object = NARROW[x]; ob2: CD.Object = NARROW[y]; RETURN [ob1.class=ob2.class AND ob1.bbox=ob2.bbox AND ob1.layer=ob2.layer AND EqualSpec[ob1, ob2]] }; Up: PROC [r: REAL] RETURNS [i: INT] = { i _ Real.Fix[r]; IF Real.Float[i]#r THEN i _ i+1; }; Create: PUBLIC PROC [text: Rope.ROPE, font: REF ANY, layer: CD.Layer, flip: BOOL_TRUE] RETURNS [ob: CD.Object] = { ENABLE UNWIND => NULL; WITH font SELECT FROM cdFont: CDFont => { insert: BOOL; used: REF; e: ImagerFont.Extents _ ImagerFont.RopeBoundingBox[cdFont.font, text]; w: REAL _ ImagerFont.RopeWidth[cdFont.font, text].x; ob _ GiveOb[]; NARROW[ob.specific, TextSpecific]^ _ [text: text, cdFont: cdFont]; ob.bbox _ [x1: -cdFont.origin.x, x2: Up[e.rightExtent], y1: -cdFont.origin.y, y2: cdFont.height-cdFont.origin.y]; ob.class _ IF flip THEN flipTextClass ELSE rigidTextClass; ob.layer _ layer; [insert: insert, used: used] _ LRUCache.Include[lruQueue, ob]; IF ~insert THEN { free _ ob; ob _ NARROW[used]; }; }; ENDCASE => NULL }; ImagerPrintFont: PUBLIC PROC [cdFont: CDTexts.CDFont] RETURNS [Imager.Font] = { RETURN [InlineImagerPrintFont[cdFont]] }; InlineImagerPrintFont: PROC [cdFont: CDTexts.CDFont] RETURNS [Imager.Font] = INLINE { WITH cdFont.data SELECT FROM printFont: Imager.Font => RETURN [printFont]; ENDCASE => { printFont: Imager.Font _ SubstituteTiogaFonts[cdFont.font]; cdFont.data _ printFont; RETURN [printFont]; }; }; FixDraw: PROC [inst: CD.Instance, trans: CD.Transformation, pr: CD.DrawRef] = { WithContext: PROC [context: Imager.Context, ob: CD.Object, layer: CD.Layer] = { tp: CDTexts.TextSpecific = NARROW[ob.specific]; Imager.SetFont[context, (IF pr.specialFonts THEN InlineImagerPrintFont[tp.cdFont] ELSE tp.cdFont.font)]; Imager.SetXY[context, [0, 0]]; --always use original font offsets! Imager.ShowRope[context, tp.text]; }; pr.drawContext[pr, WithContext, inst.ob, trans, inst.ob.layer] }; FlipTransform: PUBLIC PROC [bbox: CD.Rect, orient: CD.Orientation] RETURNS [Imager.Transformation] = { RETURN [InlineFlipTransform[bbox, orient]] }; InlineFlipTransform: PROC [bbox: CD.Rect, orient: CD.Orientation] RETURNS [Imager.Transformation] = INLINE { RETURN [SELECT orient FROM mirrorX, rotate90X => ImagerTransformation.Create[-1, 0, bbox.x2-bbox.x1, 0, 1, 0], rotate180X, rotate270X => ImagerTransformation.Create[1, 0, 0, 0, -1, bbox.y2+bbox.y1], rotate180, rotate90 => ImagerTransformation.Create[-1, 0, bbox.x2-bbox.x1, 0, -1, bbox.y2+bbox.y1], original, rotate270 => ImagerTransformation.Create[1, 0, 0, 0, 1, 0], ENDCASE => ERROR ] }; FlipDraw: PROC [inst: CD.Instance, trans: CD.Transformation, pr: CD.DrawRef] = { WithContext: PROC [context: Imager.Context, ob: CD.Object, layer: CD.Layer] = { tp: CDTexts.TextSpecific = NARROW[ob.specific]; Imager.SetFont[context, (IF pr.specialFonts THEN InlineImagerPrintFont[tp.cdFont] ELSE tp.cdFont.font)]; SELECT trans.orient FROM original, rotate270 => NULL; ENDCASE => Imager.ConcatT[context, InlineFlipTransform[ob.bbox, trans.orient]]; Imager.SetXY[context, [0, 0]]; --always use original font offsets! Imager.ShowRope[context, tp.text]; }; pr.drawContext[pr, WithContext, inst.ob, trans, inst.ob.layer] }; Describe: PROC[me: CD.Object] RETURNS [r: Rope.ROPE] = { tp: TextSpecific = NARROW[me.specific]; r _ Rope.Cat["text [", tp.text, "]"]; IF me.class#flipTextClass THEN r _ Rope.Concat["X-", r]; }; Write: CD.InternalWriteProc = { tp: TextSpecific = NARROW[ob.specific]; CDIO.WriteRect[h, ob.bbox]; TokenIO.WriteRope[h, tp.text]; WriteFont[h, tp.cdFont]; CDIO.WriteLayer[h, ob.layer]; IF ob.class=flipTextClass THEN TokenIO.WriteInt[h, 1] ELSE TokenIO.WriteInt[h, 0] }; Read: CD.InternalReadProc = { ob: CD.Object; r: CD.Rect_ [0,0,-1,-1]; t: Rope.ROPE; i: INT; cdFont: REF CDTexts.FontRec; layer: CD.Layer; IF CDIO.VersionKey[h]>15 THEN r _ CDIO.ReadRect[h] ELSE { [] _ CDIO.ReadPos[h]; }; t _ TokenIO.ReadRope[h]; cdFont _ ReadFont[h]; layer _ CDIO.ReadLayer[h]; i _ TokenIO.ReadInt[h]; ob _ Create[text: t, font: cdFont, layer: layer, flip: i=1]; IF r#ob.bbox AND CDBasics.NonEmpty[r] THEN FixSize[ob, r]; RETURN [ob] }; changeTextSizeIfDifferent: BOOL _ FALSE; changeMsg: BOOL _ FALSE; FixSize: PROC [ob: CD.Object, r: CD.Rect] = { IF r#ob.bbox THEN { TerminalIO.PutRope["** size of text wrong; probably use of different font\n"]; IF ~changeMsg THEN { TerminalIO.PutRope["** to change object sizes to the current font requirements type "" _ CDTextsImpl.changeTextSizeIfDifferent _ TRUE"" into an interpreter and read in the file again. Then set it again to FALSE\n"]; changeMsg _ TRUE; }; IF ~changeTextSizeIfDifferent THEN ob.bbox _ r; }; }; ReadFont: PROC [h: TokenIO.Handle] RETURNS [cdFont: REF CDTexts.FontRec] = { format: INT _ TokenIO.ReadInt[h]; SELECT format FROM 1 => { name: Rope.ROPE; scale: INT; name _ TokenIO.ReadRope[h]; scale _ TokenIO.ReadInt[h]; cdFont _ InternalMakeFont[name, scale, $IO]; }; ENDCASE => ERROR }; WriteFont: PROC [h: TokenIO.Handle, cdFont: CDFont] = { TokenIO.WriteInt[h, cdFont.format]; IF cdFont.format#1 THEN ERROR ELSE { TokenIO.WriteRope[h, cdFont.supposedName]; TokenIO.WriteInt[h, cdFont.scaleI]; }; }; fontCache: SymTab.Ref _ SymTab.Create[mod: 31, case: FALSE]; MakeKey: PROC [name: Rope.ROPE, scale: INT] RETURNS [Rope.ROPE] = { RETURN [IO.PutFR["!%0g*%0g", IO.rope[name], IO.int[scale]]]; }; GetCachedFont: PROC [name: Rope.ROPE, scale: CD.Number] RETURNS [REF CDTexts.FontRec] = { WITH fontCache.Fetch[MakeKey[name, scale]].val SELECT FROM f: REF CDTexts.FontRec => RETURN [f]; ENDCASE => RETURN [NIL]; }; CreateFont: PROC [name: Rope.ROPE, scale: CD.Number, approx: ATOM _ NIL] RETURNS [cdFont: REF CDTexts.FontRec_NIL] = { FindFont: PROC [name: Rope.ROPE] RETURNS [font: Imager.Font_NIL] = { font _ ImagerFont.Find[name ! Imager.Error => { font _ NIL; TerminalIO.PutRopes["**error while loading font ", name, ": "]; TerminalIO.PutRopes[error.explanation, "\n"]; CONTINUE; }; RuntimeError.UNCAUGHT => { font _ NIL; TerminalIO.PutRopes["**unknown error while loading font ", name, "\n"]; CONTINUE; } ]; }; IsIdentity: PROC [t: Imager.Transformation] RETURNS [BOOL] = { RETURN [t.a=1.0 AND t.b=0.0 AND t.c=0.0 AND t.d=0.0 AND t.e=1.0 AND t.f=0.0] }; Internalize: PROC [font: Imager.Font, scale: INT] RETURNS [cdf: REF CDTexts.FontRec_NIL] = { IF font#NIL THEN { e: ImagerFont.Extents; scale _ MAX[1, scale]; IF ~IsIdentity[font.charToClient] THEN ERROR; cdf _ NEW[CDTexts.FontRec _ [properties: CD.InitPropRef[], origin: [0, 0], xy: [0, 0], format: 1]]; cdf.scaleI _ scale; cdf.scaleR _ scale; CDProperties.PutProp[cdf.properties, $OriginalFont, font]; cdf.font _ ImagerFont.Modify[font, ImagerTransformation.Scale[scale]]; e _ ImagerFont.FontBoundingBox[cdf.font]; cdf.xy.x _ Up[e.leftExtent]; cdf.xy.y _ Up[e.descent]; cdf.height _ Up[e.ascent]+Up[e.descent]; cdf.origin.x _ Up[cdf.xy.x]; cdf.origin.y _ Up[cdf.xy.y]; } }; FindPlaceholderFont: PROC [name: Rope.ROPE] RETURNS [font: Imager.Font_NIL] = { TerminalIO.PutRopes["**font ", name, " substituted\n"]; RETURN [VFonts.defaultFont]; }; isPlaceHolder: BOOL _ FALSE; font: Imager.Font _ FindFont[name]; IF font=NIL THEN { SELECT approx FROM NIL => RETURN [NIL]; $old => { font _ OldFindFont[name]; IF font#NIL THEN name _ font.name; --to prevent bad cache entries!! }; $IO => NULL; ENDCASE => TerminalIO.PutRope["** bad font mode key\n"]; IF font=NIL THEN { isPlaceHolder _ TRUE; font _ FindPlaceholderFont[name]; }; }; IF font#NIL THEN { --exact font cdFont _ Internalize[font, scale]; cdFont.isPlaceHolder _ isPlaceHolder; cdFont.supposedKey _ MakeKey[name, scale]; cdFont.supposedName _ name; [] _ fontCache.Store[cdFont.supposedKey, cdFont]; RETURN }; }; InternalMakeFont: PROC [name: Rope.ROPE, scale: CD.Number, approx: ATOM] RETURNS [cdFont: REF FontRec] = { cdFont _ GetCachedFont[name, scale]; IF cdFont=NIL THEN cdFont _ CreateFont[name, scale, approx]; }; MakeFont: PUBLIC PROC [name: Rope.ROPE, scale: CD.Number] RETURNS [CDFont] = { RETURN [InternalMakeFont[name, scale, NIL]] }; ConvertCreateText: PROC [text: Rope.ROPE, font: REF ANY, layer: CD.Layer, key: ATOM] RETURNS [ob: CD.Object_NIL] = { WITH font SELECT FROM cdFont: CDFont => { flip: BOOL _ layer=CD.commentLayer; IF Rope.Match["*symbol*", cdFont.supposedName, FALSE] THEN flip _ FALSE; IF Rope.Match["*gate*", cdFont.supposedName, FALSE] THEN flip _ FALSE; IF key=$chipnsil OR key=$never THEN flip _ FALSE; ob _ Create[text, cdFont, layer, flip] }; ENDCASE => NULL }; neverFlip: BOOL _ FALSE; flipMsg: BOOL _ FALSE; ReadEvent: CDEvents.EventProc = { changeMsg _ flipMsg _ FALSE; }; ConvertRead: CD.InternalReadProc = { ob: CD.Object; sz: CD.Position; t: Rope.ROPE; cdFont: REF CDTexts.FontRec; layer: CD.Layer; IF CDIO.VersionKey[h]<=8 THEN RETURN [VeryOldReadText[h, NIL]]; t _ TokenIO.ReadRope[h]; layer _ CDIO.ReadLayer[h]; IF layer=CD.undefLayer AND CDIO.VersionKey[h]<=14 THEN { layer _ CD.commentLayer; TerminalIO.PutRope["** layer of text converted to comment\n"]; }; sz _ CDIO.ReadPos[h]; cdFont _ ReadFont[h]; ob _ ConvertCreateText[text: t, font: cdFont, layer: layer, key: IF neverFlip THEN $never ELSE CDIO.DesignInReadOperation[h].technology.key ]; IF ~flipMsg THEN { flipMsg _ TRUE; TerminalIO.PutRope["**did convert text to either rigid or flip text; you can guide the conversion with either\n _ CDTextsImpl.neverFlip _ TRUE\n _ CDTextsImpl.neverFlip _ FALSE\nand repeating the input\n"]; }; RETURN [ob] }; OldFindFont: PROC [name: Rope.ROPE] RETURNS [font: Imager.Font_NIL] = { FindFont: PROC [name: Rope.ROPE] RETURNS [font: Imager.Font_NIL] = { font _ ImagerFont.Find[name ! Imager.Error => {font _ NIL; CONTINUE}; RuntimeError.UNCAUGHT => {font _ NIL; CONTINUE} ]; }; BasePart: PROC [name: Rope.ROPE] RETURNS [Rope.ROPE] = { fName: Rope.ROPE; cp: FS.ComponentPositions; [fullFName: fName, cp: cp] _ FS.ExpandName[name: name]; RETURN [ Rope.Substr[fName, cp.base.start, cp.base.length] ] }; FindFontOrXFont: PROC [name: Rope.ROPE] RETURNS [font: Imager.Font_NIL] = { font _ FindFont[name]; IF font=NIL THEN font _ FindFont[Rope.Concat["Xerox/TiogaFonts/", name]]; }; TryAlso: PROC [name: Rope.ROPE] RETURNS [next: Rope.ROPE_NIL] = { IF name.Length[]>1 THEN { ch: CHAR _ name.Fetch[name.Length[]-1]; IF ch='B OR ch='I OR ch='N THEN next _ name.Substr[0, name.Length[]-1] } }; ok: BOOL _ TRUE; copy: Rope.ROPE _ BasePart[name]; name _ copy; DO font _ FindFontOrXFont[copy]; IF font#NIL THEN { IF copy#name THEN TerminalIO.PutRope[ Rope.Cat["Font ", name, " not found; use ", copy, " instead\n"] ]; RETURN; }; copy _ TryAlso[copy]; IF copy.IsEmpty[] THEN RETURN; ENDLOOP; }; VeryOldReadText: CD.InternalReadProc = { OldReadFont: PROC [h: TokenIO.Handle] RETURNS [font: REF CDTexts.FontRec] = { name: Rope.ROPE = TokenIO.ReadRope[h]; scale: INT = MAX[TokenIO.ReadInt[h]/8, 1]; --originally used a real ignoreHeight: CD.Number = TokenIO.ReadInt[h]; ignoreWhiteBorder: CD.Number = TokenIO.ReadInt[h]; ignoreLayerSubstitute: CD.Layer = CDIO.ReadLayer[h]; ignoreBaseOffsetX: REAL = TokenIO.ReadInt[h]/8.0; ignoreBaseOffsetY: REAL = TokenIO.ReadInt[h]/8.0; ignoreScaleByReplacingFontAllowed: BOOL = (1=TokenIO.ReadInt[h]); font _ InternalMakeFont[name: name, scale: scale, approx: $old]; }; ob: CD.Object; x: INT _ -1; y: INT _ -1; r: Rope.ROPE; f: ATOM; layer: CD.Layer _ CD.undefLayer; font: REF FontRec; token: TokenIO.Token _ TokenIO.Read[h]; WITH token SELECT FROM rope: TokenIO.Token.rope => r _ rope.value; -- very old int: TokenIO.Token.int => {-- less old x _ int.value; y _ TokenIO.ReadInt[h]; layer _ CDIO.ReadLayer[h]; r _ TokenIO.ReadRope[h] }; ENDCASE => ERROR TokenIO.EncodingError; f _ TokenIO.ReadAtom[h]; IF f#NIL THEN ERROR; font _ OldReadFont[h]; ob _ ConvertCreateText[text: r, font: font, layer: layer, key: NIL]; RETURN [ob] }; ChangeLayer: CD.ChangeLayerProc = { newOb: CD.Object; ts: CDTexts.TextSpecific _ NARROW[inst.ob.specific]; newLayer: CD.Layer _ CDLayers.AbstractToPaint[layer]; IF newLayer=CD.undefLayer AND newLayer#layer THEN RETURN [FALSE]; newOb _ Create[text: ts.text, font: ts.cdFont, layer: layer, flip: CDTexts.IsFlipText[inst.ob]]; IF newOb#NIL THEN inst.ob _ newOb; RETURN [newOb#NIL]; }; SubstituteTiogaFonts: PUBLIC PROC [imagerFont: Imager.Font] RETURNS [printFont: Imager.Font] = { shortFName, subDir, fullFName, family, attributes: Rope.ROPE; cp: FS.ComponentPositions; sizePos, facePos, attributesLeng: INT; size: REAL; face: NodeStyle.FontFace _ Regular; [fullFName, cp] _ FS.ExpandName[imagerFont.name]; printFont _ imagerFont; subDir _ Rope.Substr[fullFName, cp.subDirs.start, cp.subDirs.length]; IF Rope.Equal[subDir, "Xerox>TiogaFonts", FALSE] THEN { shortFName _ Rope.Substr[fullFName, cp.base.start, cp.base.length]; sizePos _ Rope.SkipTo[shortFName, 0, "0123456789"]; attributesLeng _ Rope.Length[shortFName]-sizePos; attributes _ Rope.Substr[shortFName, sizePos, attributesLeng]; facePos _ Rope.SkipTo[attributes, 0, "bBiI"]; size _ (ORD[Rope.Fetch[attributes, 0]] - ORD ['0]); FOR i: INT IN [1..facePos) DO size _ size * 10.0 + (ORD[Rope.Fetch[attributes, i]] - ORD['0]) ENDLOOP; IF facePos#attributesLeng THEN { it: BOOL ~ Rope.SkipTo[attributes, 0, "iI"]#attributesLeng; b: BOOL ~ Rope.SkipTo[attributes, 0, "bB"]#attributesLeng; SELECT TRUE FROM it AND b => face _ BoldItalic; it AND NOT b => face _ Italic; NOT it AND b => face _ Bold; ENDCASE => ERROR }; family _ Rope.Substr[shortFName, 0, sizePos]; printFont _ NodeStyleFont.FontFromStyleParams[prefix: Atom.MakeAtom["Xerox/PressFonts/"], family: Atom.MakeAtom[family], face: face, size: size, alphabets: CapsAndLower]; IF printFont=NIL THEN RETURN [imagerFont]; printFont _ ImagerFont.Modify[printFont, imagerFont.charToClient] }; }; [] _ CDProperties.RegisterProperty[$OriginalFont, $CDTextsImpl]; CDEvents.RegisterEventProc[$ReadTechnologyPrivate, ReadEvent]; END. CDTextsImpl.mesa Copyright c 1983, 1986 by Xerox Corporation. All rights reserved. Created by Christian Jacobi, July 29, 1983 11:17 am Last Edited by: Christian Jacobi, December 16, 1986 12:59:06 pm PST -- returns integer i: i >= r; there exists no integer j such that j < i and j >= r --don't clip: speed; --Imager.ClipRectangle[context, [x: ob.bbox.x1, y: ob.bbox.y1, w: ob.bbox.x2-ob.bbox.x1, h: ob.bbox.y2-ob.bbox.y1]]; --matrix multiplications done manually for speed --thats what it really means original, rotate270 => ImagerTransformation.Scale[1], mirrorX, rotate90X => ImagerTransformation.Concat[ ImagerTransformation.Translate[[bbox.x1-bbox.x2, 0]], ImagerTransformation.Scale2[[-1, 1]] ], rotate180X, rotate270X => ImagerTransformation.Cat[ ImagerTransformation.Translate[[bbox.x1-bbox.x2, -bbox.y2-bbox.y1]], ImagerTransformation.Rotate[180], ImagerTransformation.Translate[[bbox.x1-bbox.x2, 0]], ImagerTransformation.Scale2[[-1, 1]] ], rotate180, rotate90 => ImagerTransformation.Concat[ ImagerTransformation.Translate[[bbox.x1-bbox.x2, -bbox.y2-bbox.y1]], ImagerTransformation.Rotate[180] ], --don't clip: speed; --Imager.ClipRectangle[context, [x: ob.bbox.x1, y: ob.bbox.y1, w: ob.bbox.x2-ob.bbox.x1, h: ob.bbox.y2-ob.bbox.y1]]; mirrorX, rotate90X => { Imager.Scale2T[context, [-1, 1]]; Imager.TranslateT[context, [ob.bbox.x1-ob.bbox.x2, 0]]; }; rotate180X, rotate270X => { Imager.Scale2T[context, [-1, 1]]; Imager.TranslateT[context, [ob.bbox.x1-ob.bbox.x2, 0]]; Imager.RotateT[context, 180]; Imager.TranslateT[context, [ob.bbox.x1-ob.bbox.x2, -ob.bbox.y2-ob.bbox.y1]]; }; rotate180, rotate90 => { Imager.RotateT[context, 180]; Imager.TranslateT[context, [ob.bbox.x1-ob.bbox.x2, -ob.bbox.y2-ob.bbox.y1]]; }; -- Fonts ======================================== -- Old ======================================== --originally did compare size of text with sz --get rid of a B or I (for Bold or Italic) --we don't handle ropes of length 0 and 1 --for version<=8 --originally did check size of text with x and y --Translates from strike to spline fonts. --Procedure copied from Giordano's original version in Nectarine. --Construct the old style name: --Find the size and face from the old style name: --Compute the size (assume: there always is a size): --Determine the face: ʧ˜codešœ™Kšœ Ïmœ7™BKšœ4™4K™C—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šœ˜Kšœ˜—K˜šÏn œžœžœ˜Kš žœžœžœ žœ8žœ,žœX˜áKšžœ˜$—Kšž˜K˜Kšœžœ˜*Kšœ žœ˜ Kšœ žœ˜ Kšœžœ˜K˜šœžœžœžœ˜EKšœ˜Kšœ˜—šœžœžœžœ"˜LKšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—šœžœžœžœ!˜JKšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ žœžœ˜1K˜KšœH˜HKšœžœ žœ˜K˜š Ÿœžœžœžœžœ ˜1Kšœžœ˜šžœžœžœ˜Kšœžœžœžœ ˜0—K˜—K˜š Ÿœžœžœžœžœ˜)š Ÿ œžœžœ žœžœ˜3Kšœžœ ˜'Kšœžœ ˜'šžœ˜Kšœžœžœ˜)Kšœ;žœ˜@Kšœ˜—K˜—Kšœžœ žœ˜Kšœžœ žœ˜Kšžœžœžœžœ˜bKšœ˜—K˜š Ÿœžœžœžœžœ˜'K™TKšœ˜Kšžœžœ ˜ K˜K˜—šŸœžœžœ žœžœžœ žœžœžœžœžœ ˜rKšžœžœžœ˜šžœžœž˜šœ˜Kšœžœžœ˜KšœF˜FKšœžœ-˜4Kšœ˜Kšžœ<˜BKšœq˜qKšœ žœžœžœ˜:Kšœ˜Kšœ>˜>šžœ žœ˜Kšœžœ˜Kšœ˜—K˜—Kšžœž˜—Kšœ˜K˜—šŸœž œžœ˜OKšžœ ˜&Kšœ˜—K˜šŸœžœžœžœ˜Ušžœ žœž˜Kšœžœ ˜-šžœ˜ KšœT˜TKšžœ ˜K˜——K˜—K˜š Ÿœžœžœžœžœ ˜OK˜šŸ œžœžœžœ ˜OKšœžœ˜/KšÏc™Kš t™tKšœžœžœ"žœ˜hKšœ #˜BKšœ"˜"Kšœ˜—K˜Kšœ>˜>Kšœ˜—K˜š Ÿ œžœžœžœžœžœ˜fKšžœ$˜*K˜—K˜š Ÿœžœžœžœžœžœ˜lšžœžœž˜Kš 0™0KšœS˜SKšœW˜WKšœc˜cKšœE˜EK™š ™Kšœ5™5šœ2™2Kšœ6™6Kšœ$™$Kšœ™—šœ3™3KšœE™EKšœ!™!Kšœ6™6Kšœ$™$Kšœ™—šœ3™3KšœE™EKšœ ™ Kšœ™———˜Kšžœž˜K˜—J˜—K˜š Ÿœžœžœžœžœ ˜PK˜šŸ œžœžœžœ ˜OKšœžœ˜/Kš ™Kš t™tKšœžœžœ"žœ˜hšžœž˜Kšœžœ˜šœ™Kšœ[™[Kšœ™—šœ™Kšœ[™[Kšœl™lK™—šœ™Kšœl™lK™—KšžœI˜P—Kšœ #˜BKšœ"˜"Kšœ˜—K˜Kšœ>˜>Kšœ˜—K˜š Ÿœžœžœ žœ žœ˜8Kšœžœ˜'Kšœ%˜%Kšžœžœ˜8Kšœ˜—K˜šÐbnœžœ˜Kšœžœ˜'Kšžœ˜Kšœ˜Kšœ˜Kšžœ˜Kšžœžœžœ˜QKšœ˜—K˜š¡œžœ˜Kšœžœ žœ˜(Kšœžœžœ˜Kšœžœžœ˜-Kšžœžœžœžœ ˜2šžœ˜Kšœžœ ˜K˜—Kšœ˜Kšœ˜Kšœžœ˜Kšœ˜Kšœ<˜Kš žœ žœ žœ žœ žœ žœ ˜LKšœ˜—K˜š Ÿ œžœžœžœžœžœ˜\šžœžœžœ˜Kšœ˜Kšœžœ ˜Kšžœ žœžœ˜-Kšœžœ žœ8˜cKšœ˜Kšœ˜Kšœ:˜:KšœF˜FKšœ)˜)Kšœ˜Kšœ˜Kšœ(˜(Kšœ˜Kšœ˜K˜—Kšœ˜—K˜š Ÿœžœ žœžœžœ˜OKšœ7˜7Kšžœ˜Kšœ˜—K˜Kšœžœžœ˜Kšœ#˜#šžœžœžœ˜šžœž˜Kšžœžœžœ˜šœ ˜ Kšœ˜Kšžœžœžœ  ˜CK˜—Kšœžœ˜ Kšžœ1˜8—šžœžœžœ˜Kšœžœ˜Kšœ!˜!K˜—K˜—šžœžœžœ  ˜Kšœ"˜"Kšœ%˜%Kšœ*˜*Kšœ˜Kšœ1˜1Kšž˜K˜—Kšœ˜—K˜šŸœžœ žœ žœžœžœ žœ ˜jKšœ$˜$Kšžœžœžœ*˜˜>Kšœ˜—Kšœžœ ˜Kšœ˜šœ<˜˜>Kšœ-˜-Kš 4™4Kšœžœžœ˜3šžœžœžœž˜Kšœžœžœ˜?Kšžœ˜—Kš ™šžœžœ˜ Kšœžœ3˜;Kšœžœ3˜:šžœžœž˜Kšœžœ˜Kšœžœžœ˜Kšžœžœ˜Kšžœž˜—Kšœ˜—Kšœ-˜-Kšœª˜ªKšžœ žœžœžœ˜*KšœA˜AKšœ˜—Kšœ˜—K˜Kšœ@˜@Kšœ>˜>Kšžœ˜K˜K™—…—<î[Ÿ