DIRECTORY BasicTime USING [GMT, nullGMT], Convert USING [Error, RealFromRope], FS USING [Error], Icons USING [IconFlavor, NewIconFromFile], Imager USING [Box, ConstantColor, Context, RotateT, ScaleT], ImagerColor USING [GrayFromColor, RGB], ImagerColorMap USING [LoadEntries, MapEntry, SetStandardColorMap], ImagerDitheredDevice USING [ColorFromSpecialRGB], ImagerInterpress USING [Close, Create, DoPage, Ref], ImagerPress USING [Close, SimpleCreate], IO USING [int, PutFR], Menus USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuProc], MessageWindow USING [Append, Blink], Plot USING [Curves, PlotSpec, PlotSpecRec, ReadPlotFile, RopeSequence, SavePlot, Vector], PlotOps USING [BackgroundType, ColorMap, ColorMode, DrawMe, Handle, HandleData, LineState, LineStateRec, LineStep, Lock, NColors, OutputType, StateSequence, Unlock], PopUpMenu USING [RequestSelection], Real USING [RoundC], Rope USING [Cat, Equal, Find, IsEmpty, ROPE, Substr], Terminal USING [ColorCursorPresentation, Current, GetColorCursorPresentation, SetColorCursorPresentation, Virtual], UserProfile USING [CallWhenProfileChanges, ListOfTokens, ProfileChangedProc, Token], ViewerClasses USING [Column, PaintProc, Viewer, ViewerClass, ViewerClassRec], ViewerOps USING [CreateViewer, EnumerateViewers, EnumProc, OpenIcon, PaintViewer, RegisterViewerClass, SwapIconAndViewer], ViewerTools USING [GetSelectionContents], WindowManager USING [colorDisplayOn, RestoreCursor]; PlotViewer: CEDAR PROGRAM IMPORTS Convert, FS, Imager, ImagerColor, ImagerColorMap, ImagerDitheredDevice, ImagerInterpress, ImagerPress, Icons, IO, Menus, MessageWindow, Plot, PlotOps, PopUpMenu, Real, Rope, Terminal, UserProfile, ViewerOps, ViewerTools, WindowManager EXPORTS Plot, PlotOps = { OPEN Plot, PlotOps; coordRatio: REAL = 0.25/600.0; -- 0.25 m ~ 600 pixels plotIcon: Icons.IconFlavor _ Icons.NewIconFromFile["Plot.icons", 0]; plotViewerClass: ViewerClasses.ViewerClass _ NEW [ViewerClasses.ViewerClassRec _ [paint: Display, icon: plotIcon, cursor: textPointer]]; virtual: Terminal.Virtual = Terminal.Current[]; initialColumn: ViewerClasses.Column; -- {static, left, right, color} createOption: {closeOtherViewers, swapLastViewer, iconic, badCreateOption}; backgroundType: BackgroundType; -- {white, gray, darkGray, black, unknown} color: PUBLIC ARRAY NColors OF Imager.ConstantColor; CreateViewer: PUBLIC PROC [spec: PlotSpec _ NIL, iconic, inhibitDestroy: BOOL _ FALSE] RETURNS [viewer: ViewerClasses.Viewer _ NIL] = { handle: Handle _ NEW[HandleData _ [ plotSpec: spec, background: backgroundType ] ]; viewer _ ViewerOps.CreateViewer[ flavor: $Plot, info: [ name: spec.file, menu: MakeMenu[], icon: plotIcon, column: initialColumn, iconic: TRUE, inhibitDestroy: inhibitDestroy, data: handle], paint: FALSE]; IF iconic OR (createOption = iconic) THEN ViewerOps.PaintViewer[viewer, all, TRUE, NIL] ELSE { SELECT createOption FROM closeOtherViewers => ViewerOps.OpenIcon[ icon: viewer, closeOthers: TRUE, bottom: TRUE, paint: TRUE]; swapLastViewer => { vLast: ViewerClasses.Viewer _ NIL; LastViewer: ViewerOps.EnumProc = { IF v.column = initialColumn AND NOT v.iconic THEN {vLast _ v; RETURN[FALSE]}; }; -- LastViewer ViewerOps.EnumerateViewers[LastViewer]; IF vLast = NIL THEN ViewerOps.OpenIcon[ icon: viewer, closeOthers: TRUE, bottom: TRUE, paint: TRUE] ELSE { ViewerOps.SwapIconAndViewer[ icon: viewer, openViewer: vLast, paint: TRUE]; -- this paints the new viewer only. ViewerOps.PaintViewer[vLast, all, TRUE, NIL]; -- paint the last viewer. }; }; ENDCASE; }; }; -- CreateViewer AddVector: PUBLIC PROC [viewer: ViewerClasses.Viewer _ NIL, vector: Vector _ NIL] = { IF vector = NIL OR NOT IsPlotViewer[viewer] THEN RETURN ELSE { shouldPaint: BOOL _ FALSE; expectedSize: CARDINAL; handle: Handle _ NARROW[viewer.data]; IF handle # NIL THEN { Lock[handle]; expectedSize _ handle.plotSpec.nCurvesMax + 1; IF vector.size # expectedSize THEN MessageWindow.Append[ IO.PutFR["Only %g elements in vector when %g expected.", IO.int[vector.size], IO.int[expectedSize]], TRUE] ELSE { IF handle.curves = NIL THEN { handle.lineStates _ NEW[StateSequence[handle.plotSpec.nCurvesMax]]; FOR i: CARDINAL IN[0..handle.plotSpec.nCurvesMax) DO handle.lineStates[i] _ NEW[LineStateRec _ []]; ENDLOOP; } ELSE IF handle.curves.first # NIL THEN shouldPaint _ TRUE; handle.curves _ CONS[vector, handle.curves] }; Unlock[handle]; }; IF shouldPaint THEN ViewerOps.PaintViewer[viewer, client, FALSE, handle.curves]; }; }; -- AddVector CreateSpec: PUBLIC PROC[file, title: Rope.ROPE _ NIL, time: BasicTime.GMT _ BasicTime.nullGMT, bounds: Imager.Box _ [0, 0, 0, 0], -- [xmin, xmax, ymin, ymax] nCurvesMax: CARDINAL _ 0, legendEntries: REF RopeSequence _ NIL ] RETURNS[spec: PlotSpec _ NIL] = { spec _ NEW[PlotSpecRec _ [file, title, time, bounds, nCurvesMax, legendEntries]]; }; -- CreateSpec SetSpec: PUBLIC PROC [viewer: ViewerClasses.Viewer _ NIL, newSpec: PlotSpec _ NIL] = { IF IsPlotViewer[viewer] THEN { handle: Handle _ NARROW[viewer.data]; IF handle = NIL THEN RETURN; Lock[handle]; handle.curves _ NIL; handle.plotSpec _ newSpec; viewer.name _ handle.plotSpec.file; Unlock[handle]; ViewerOps.PaintViewer[viewer, caption, FALSE, NIL]; ViewerOps.PaintViewer[viewer, client, TRUE, NIL]; -- update the display. }; }; -- SetSpec Clear: PUBLIC PROC [viewer: ViewerClasses.Viewer] = { IF IsPlotViewer[viewer] THEN { handle: Handle _ NARROW[viewer.data]; Lock[handle]; handle.plotSpec^ _ []; handle.curves _ NIL; Unlock[handle]; ViewerOps.PaintViewer[viewer, client, TRUE, NIL]; }; }; -- Clear Zoom: PUBLIC PROC [viewer: ViewerClasses.Viewer, newBounds: Imager.Box] = { IF IsPlotViewer[viewer] THEN { handle: Handle _ NARROW[viewer.data]; Lock[handle]; handle.plotSpec.bounds _ newBounds; Unlock[handle]; ViewerOps.PaintViewer[viewer, client, TRUE, NIL]; }; }; -- Zoom IsPlotViewer: PUBLIC PROC [viewer: ViewerClasses.Viewer] RETURNS [BOOL] = { IF viewer = NIL THEN RETURN[FALSE]; RETURN[viewer.class.flavor = $Plot]; }; -- IsPlotViewer SetColorMap: Menus.MenuProc = { viewer: ViewerClasses.Viewer _ NARROW[parent]; handle: Handle _ NARROW[viewer.data]; IF handle # NIL THEN { newColorMap: ColorMap = SELECT PopUpMenu.RequestSelection[ label: "Options", choice: LIST["mine", "Cedar"], default: 1] FROM 1 => mine, 2 => cedar, ENDCASE => handle.colorMap; Lock[handle]; SetCursorForBackgroundType[handle.background]; IF handle.colorMap # newColorMap THEN { handle.colorMap _ newColorMap; SELECT newColorMap FROM mine => SetMyColorMap[]; cedar => SetCedarColorMap[]; ENDCASE; }; Unlock[handle]; }; }; -- SetColorMap SetDisplayMode: Menus.MenuProc = { viewer: ViewerClasses.Viewer _ NARROW[parent]; handle: Handle _ NARROW[viewer.data]; IF handle # NIL THEN { newColorMode: ColorMode = SELECT PopUpMenu.RequestSelection[ label: "Options", choice: LIST["color", "black and white"], default: 1] FROM 1 => color, 2 => bw, ENDCASE => handle.colorMode; changed: BOOL; Lock[handle]; SetCursorForBackgroundType[handle.background]; changed _ handle.colorMode # newColorMode; handle.colorMode _ newColorMode; Unlock[handle]; IF changed THEN ViewerOps.PaintViewer[viewer, client, TRUE, NIL]; }; }; -- SetDisplayMode SetCursorColor: Menus.MenuProc = { viewer: ViewerClasses.Viewer _ NARROW[parent]; handle: Handle _ NARROW[viewer.data]; IF handle # NIL THEN { SELECT PopUpMenu.RequestSelection[ label: "Options", choice: LIST["black", "white"], default: 1] FROM 1 => [] _ Terminal.SetColorCursorPresentation[virtual, onesAreBlack]; 2 => [] _ Terminal.SetColorCursorPresentation[virtual, onesAreWhite]; ENDCASE => { Lock[handle]; SetCursorForBackgroundType[handle.background]; Unlock[handle]; }; }; }; -- SetCursorColor SetBackgroundType: Menus.MenuProc = { viewer: ViewerClasses.Viewer _ NARROW[parent]; handle: Handle _ NARROW[viewer.data]; IF handle # NIL THEN { newBkGndType: BackgroundType = SELECT PopUpMenu.RequestSelection[ label: "Options", choice: LIST["white", "gray", "dark gray", "black"], default: 1] FROM 1 => white, 2 => gray, 3 => darkGray, 4 => black, ENDCASE => handle.background; changed: BOOL; Lock[handle]; changed _ handle.background # newBkGndType; handle.background _ newBkGndType; SetCursorForBackgroundType[handle.background]; Unlock[handle]; IF changed THEN ViewerOps.PaintViewer[viewer, client, TRUE, NIL]; }; }; -- SetBackgroundType Get: Menus.MenuProc = { viewer: ViewerClasses.Viewer _ NARROW[parent]; handle: Handle _ NARROW[viewer.data]; name: Rope.ROPE _ ViewerTools.GetSelectionContents[]; msg: Rope.ROPE _ IF name.IsEmpty[] THEN "Please select a plot file name." ELSE IF handle = NIL THEN "Not a good plot viewer." ELSE ReadPlotFile[name: name, viewer: viewer, iconic: FALSE]; IF msg # NIL THEN { MessageWindow.Blink[]; MessageWindow.Append[msg, TRUE]; }; }; -- Get Store: Menus.MenuProc = { viewer: ViewerClasses.Viewer _ NARROW[parent]; name: Rope.ROPE _ ViewerTools.GetSelectionContents[]; msg: Rope.ROPE _ SavePlot[viewer, name]; -- viewer type checked there IF msg # NIL THEN { MessageWindow.Blink[]; MessageWindow.Append[message: msg, clearFirst: TRUE]; }; }; -- Store Press: Menus.MenuProc = {Print[NARROW[parent], press]}; -- Press Interpress: Menus.MenuProc = {Print[NARROW[parent], interpress]}; -- Interpress AppendExtension: PROC[old, ext: Rope.ROPE _ NIL] RETURNS [Rope.ROPE]= { excl: INT _ old.Find["!"]; RETURN[Rope.Cat[ SELECT excl FROM < 0 => old, > 0 => old.Substr[0, excl], ENDCASE => "Plot", -- unlikely, though. ".", ext]]; }; -- AppendExtension GetPrintingColorMode: PROC[] RETURNS [type: ColorMode, ok: BOOL _ TRUE] = { colorChoice: NAT = PopUpMenu.RequestSelection[ label: "Options", choice: LIST["color", "black and white"], default: 1]; SELECT colorChoice FROM 1 => type _ color; 2 => type _ bw; ENDCASE => { MessageWindow.Blink[]; MessageWindow.Append[ "You must choose either color or black-and-white.", TRUE]; ok _ FALSE; }; }; -- GetPrintingColor Print: PROC[viewer: ViewerClasses.Viewer, output: OutputType _ interpress] = { handle: Handle _ NARROW[viewer.data]; printingColorMode: ColorMode; okToPrint: BOOL; IF handle = NIL THEN RETURN; [printingColorMode, okToPrint] _ GetPrintingColorMode[]; Lock[handle]; SetCursorForBackgroundType[handle.background]; IF okToPrint THEN { context: Imager.Context _ NIL; interpress: ImagerInterpress.Ref _ NIL; fileName: Rope.ROPE; colorModeSave: ColorMode; colorModeSave _ handle.colorMode; handle.colorMode _ printingColorMode; SELECT output FROM interpress => { InterpressDrawMe: PROC[context: Imager.Context] ~ { context.RotateT[90]; context.ScaleT[coordRatio]; DrawMe[context, handle, NIL, interpress]; }; fileName _ AppendExtension[handle.plotSpec.file, "ip"]; interpress _ ImagerInterpress.Create[fileName ! FS.Error => { MessageWindow.Append[error.explanation, TRUE]; CONTINUE; } ]; ImagerInterpress.DoPage[interpress, InterpressDrawMe]; MessageWindow.Append[Rope.Cat[fileName, " is written."], TRUE]; }; press => { fileName _ AppendExtension[handle.plotSpec.file, "press"]; context _ ImagerPress.SimpleCreate[fileName ! FS.Error => { MessageWindow.Append[error.explanation, TRUE]; CONTINUE; } ]; context.RotateT[90]; context.ScaleT[coordRatio]; DrawMe[context, handle, NIL, press]; MessageWindow.Append[Rope.Cat[fileName, " is written."], TRUE]; }; ENDCASE; -- (error) IF output = interpress AND interpress # NIL THEN ImagerInterpress.Close[interpress] ELSE IF output = press AND context # NIL THEN ImagerPress.Close[context]; handle.colorMode _ colorModeSave; }; Unlock[handle]; }; -- Print SetCedarColorMap: PROC [] = { ImagerColorMap.SetStandardColorMap[virtual]; WindowManager.RestoreCursor[]; IF Terminal.GetColorCursorPresentation[virtual] # onesAreBlack THEN [] _ Terminal.SetColorCursorPresentation[virtual, onesAreBlack]; }; -- SetCedarColorMap SetMyColorMap: PROC [] = { defaultRGB: ARRAY NColors OF ImagerColor.RGB _ [ [R: 1.0, G: 1.0, B: 1.0], [R: 1.0, G: 0.0, B: 0.8], -- purple red [R: 0.4, G: 0.0, B: 1.0], -- purple [R: 0.0, G: 0.0, B: 1.0], -- blue [R: 0.0, G: 0.56, B: 1.0], -- greenish blue [R: 0.0, G: 1.0, B: 1.0], -- green blue [R: 0.0, G: 1.0, B: 0.0], -- green [R: 0.52, G: 1.0, B: 0.0], -- yellow green [R: 1.0, G: 1.0, B: 0.0], -- yellow [R: 1.0, G: 0.60, B: 0.0], -- orange yellow [R: 1.0, G: 0.42, B: 0.0], -- yellowish orange [R: 1.0, G: 0.25, B: 0.0], -- orange [R: 1.0, G: 0.0, B: 0.0], -- red [R: 0.5, G: 0.5, B: 0.5], -- gray [R: 0.17, G: 0.17, B: 0.17], -- dark gray [R: 0.0, G: 0.0, B: 0.0] -- black ]; GetColor: PROC [num: NColors] RETURNS [ImagerColor.RGB] = { ColorSpec: TYPE = LIST OF Rope.ROPE; list: ColorSpec _ UserProfile.ListOfTokens[ key: IO.PutFR["Plot.Color%g", IO.int[num]], default: NIL ]; c: ARRAY[1..3] OF REAL _ [defaultRGB[num].R, defaultRGB[num].G, defaultRGB[num].B]; i: CARDINAL _ 1; FOR lr: ColorSpec _ list, list.rest UNTIL list = NIL OR i > 3 DO c[i] _ Convert.RealFromRope[list.first ! Convert.Error => EXIT]; c[i] _ MAX[0, MIN[1.0, c[i]]]; i _ i + 1; ENDLOOP; RETURN[[R: c[1], G: c[2], B: c[3]]]; }; -- GetColor FOR i: NColors IN NColors DO c: ImagerColor.RGB _ GetColor[i]; entry: ImagerColorMap.MapEntry _ [ mapIndex: i+100, red: Real.RoundC[c.R*255], green: Real.RoundC[c.G*255], blue: Real.RoundC[c.B*255] ]; ImagerColorMap.LoadEntries[ vt: virtual, mapEntries: LIST[entry], shared: FALSE]; color[i] _ ImagerDitheredDevice.ColorFromSpecialRGB[ specialPixel: [i+100, null], rgb: c]; ENDLOOP; }; -- SetMyColorMap Display: ViewerClasses.PaintProc = { IF IsPlotViewer[self] AND NOT self.iconic THEN { handle: Handle _ NARROW[self.data]; IF handle # NIL THEN { Lock[handle]; DrawMe[context, handle, whatChanged, screen]; Unlock[handle]; }; }; }; -- Display MakeMenu: PROC [] RETURNS [menu: Menus.Menu] = { menu _ Menus.CreateMenu[]; Menus.AppendMenuEntry [menu, Menus.CreateEntry["DisplayMode", SetDisplayMode]]; Menus.AppendMenuEntry [menu, Menus.CreateEntry["ColorMap", SetColorMap]]; Menus.AppendMenuEntry [menu, Menus.CreateEntry["Cursor", SetCursorColor]]; Menus.AppendMenuEntry [menu, Menus.CreateEntry["Background", SetBackgroundType]]; Menus.AppendMenuEntry [menu, Menus.CreateEntry[name: "Get", proc: Get, guarded: TRUE]]; Menus.AppendMenuEntry [menu, Menus.CreateEntry["Store", Store]]; Menus.AppendMenuEntry [menu, Menus.CreateEntry["Press", Press]]; Menus.AppendMenuEntry [menu, Menus.CreateEntry["Interpress", Interpress]]; }; -- MakeMenus ProcessUserProfile: UserProfile.ProfileChangedProc = { rope: Rope.ROPE _ UserProfile.Token[key: "Plot.Column", default: "color"]; initialColumn _ SELECT TRUE FROM rope.Equal["color", FALSE] => color, rope.Equal["left", FALSE] => left, rope.Equal["right", FALSE] => right, ENDCASE => static; IF initialColumn = static THEN { MessageWindow.Append[ Rope.Cat["Warning: Illegal entry in user profile, Plot.Column: ", rope, "."], TRUE]; initialColumn _ color; }; IF initialColumn = color AND NOT WindowManager.colorDisplayOn THEN initialColumn _ left; rope _ UserProfile.Token[key: "Plot.CreateOption", default: "closeOtherViewers"]; createOption _ SELECT TRUE FROM rope.Equal["closeOtherViewers", FALSE] => closeOtherViewers, rope.Equal["swapLastViewer", FALSE] => swapLastViewer, rope.Equal["iconic", FALSE] => iconic, ENDCASE => badCreateOption; IF createOption = badCreateOption THEN { MessageWindow.Append[ Rope.Cat["Warning: Illegal entry in user profile, Plot.CreateOption: ", rope, "."], TRUE]; createOption _ closeOtherViewers; }; rope _ UserProfile.Token[key: "Plot.Background", default: "white"]; backgroundType _ SELECT TRUE FROM rope.Equal["white", FALSE] => white, rope.Equal["gray", FALSE] => gray, rope.Equal["darkGray", FALSE] => darkGray, rope.Equal["black", FALSE] => black, ENDCASE => unknown; IF backgroundType = unknown THEN { MessageWindow.Append[ Rope.Cat["Warning: Illegal entry in user profile, Plot.Background: ", rope, "."], TRUE]; backgroundType _ white; }; SetMyColorMap[]; SetCursorForBackgroundType[backgroundType]; }; -- ProcessUserProfile SetCursorForBackgroundType: PROC [bkgnd: BackgroundType _ white] = { bkGndColor: Imager.ConstantColor _ SELECT bkgnd FROM gray => color[13], darkGray => color[14], black => color[15], ENDCASE => color[0]; cursorType: Terminal.ColorCursorPresentation _ IF ImagerColor.GrayFromColor[bkGndColor] > 0.5 THEN onesAreWhite ELSE onesAreBlack; IF cursorType # Terminal.GetColorCursorPresentation[virtual] THEN [] _ Terminal.SetColorCursorPresentation[virtual, cursorType]; }; -- SetCursorForBackgroundType Init: PROC [] = { ViewerOps.RegisterViewerClass[$Plot, plotViewerClass]; ProcessUserProfile[firstTime]; UserProfile.CallWhenProfileChanges[ProcessUserProfile]; }; -- Init Init[]; }. CHANGE LOG. Created by: SChen in Cedar5. SChen, May 14, 1985 5:39:02 pm PDT, custom icon. SChen, July 11, 1985 11:03:15 pm PDT, => Cedar6.0 (CG, press => Imager, Interpress). SChen, August 2, 1985 7:08:18 pm PDT, split it into PlotViewer and PlotViewerPaint, cleaned up some stuff related to color display and color map, added pop up menus. File: PlotViewer.mesa, Copyright (C) 1985 by Xerox Corporation. All rights reserved. Last Edited by: Sweetsun Chen, August 2, 1985 9:41:16 pm PDT constants (constant) variables parameters initialized or updated by ProcessUserProfile public procedures handle Note: lineStates[n] is the state of curve # n+1. Note: if original nCurvesMax # new one, then old data will be cleared. menu commands [parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL] white forgeround colors, all vivid gray black get color spec from user profile, or return default }; }; other private procedures [self: Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL] there will be no checking of the viewer class in DrawMe. initialColumn createOption backgroundType colors Κ΅˜JšœU™Ušœ™Jšœ,™,J™—šΟk ˜ Jšœ œœ ˜Jšœœ˜$Jšœœ ˜Jšœœ˜*Jšœœ0˜Jšœ œœ˜Jšœœ˜Jšœœ˜%šœ œœ˜J˜ Jšœ.˜.šœœ˜8Jšœ6˜8Jšœœœ˜1—šœ˜šœœœ˜šœœ,˜CJšœ0™0—šœœœ ˜4Jšœœ˜.Jšœ˜—J˜—Jšœœœœ˜:Jšœœ˜+J˜—J˜J˜—Jšœ œ'œ˜PJ˜—Jšœž ˜J˜—š Ÿ œœœœœ˜5Jšœœ˜(Jšœ#ž˜>Jšœ œ˜Jšœœ˜%Jšœœœ˜#JšœœG˜QJšœž ˜J˜—š Ÿœœœ!œœ˜VJšœF™Fšœœ˜Jšœœ˜%Jšœ œœœ˜J˜ Jšœœ˜Jšœ˜Jšœ#˜#J˜Jšœ'œœ˜3Jšœ&œœž˜HJ˜—Jšœž ˜ J˜—šŸœœœ#˜5šœœ˜Jšœœ˜%J˜ Jšœ˜Jšœœ˜J˜Jšœ&œœ˜1J˜—Jšœž˜ J˜—šŸœœœ:˜Kšœœ˜Jšœœ˜%J˜ J˜#J˜Jšœ&œœ˜1J˜—Jšœž˜ J˜—š Ÿ œœœ œœ˜KJš œ œœœœ˜#Jšœ˜$Jšœž˜—J˜šœ ™ J˜—šœ˜JšœN™NJšœœ ˜.Jšœœ˜%šœ œœ˜šœœ˜:Jšœ˜Jšœœ˜Jšœ ˜Jšœ œ˜2—J˜J˜ Jšœ.˜.šœœ˜'Jšœ˜šœ ˜Jšœ˜Jšœ˜Jšœ˜—J˜—J˜J˜—Jšœž˜J˜—šœ"˜"Jšœœ ˜.Jšœœ˜%šœ œœ˜šœœ˜œ ˜R—šœ.˜.Jšœ-œœ˜S—šœ;˜AJšœ>˜>—Jšœž˜ J˜—šŸœœ˜Jšœ6˜6Jšœ˜J˜7Jšœž˜ —J˜J˜Jšœ˜J˜šœœ˜ J˜J˜0J˜TJ˜₯——…—BXα