GLUT-2.7.0.16/cbits/0000755000000000000000000000000013255126367012024 5ustar0000000000000000GLUT-2.7.0.16/examples/0000755000000000000000000000000012642417607012535 5ustar0000000000000000GLUT-2.7.0.16/examples/BOGLGP/0000755000000000000000000000000012642417607013507 5ustar0000000000000000GLUT-2.7.0.16/examples/BOGLGP/Chapter01/0000755000000000000000000000000013255126367015237 5ustar0000000000000000GLUT-2.7.0.16/examples/BOGLGP/Chapter02/0000755000000000000000000000000013255126367015240 5ustar0000000000000000GLUT-2.7.0.16/examples/BOGLGP/Chapter03/0000755000000000000000000000000013255126367015241 5ustar0000000000000000GLUT-2.7.0.16/examples/Misc/0000755000000000000000000000000013255126367013431 5ustar0000000000000000GLUT-2.7.0.16/examples/Misc/ColorTriangle/0000755000000000000000000000000013255126367016175 5ustar0000000000000000GLUT-2.7.0.16/examples/OrangeBook/0000755000000000000000000000000012642417607014563 5ustar0000000000000000GLUT-2.7.0.16/examples/OrangeBook/ogl2brick/0000755000000000000000000000000013255126367016442 5ustar0000000000000000GLUT-2.7.0.16/examples/RedBook4/0000755000000000000000000000000013255126367014147 5ustar0000000000000000GLUT-2.7.0.16/examples/RedBook4/Data/0000755000000000000000000000000012604702100014776 5ustar0000000000000000GLUT-2.7.0.16/examples/RedBook8/0000755000000000000000000000000012642417607014152 5ustar0000000000000000GLUT-2.7.0.16/examples/RedBook8/Chapter01/0000755000000000000000000000000013255126367015702 5ustar0000000000000000GLUT-2.7.0.16/examples/RedBook8/common/0000755000000000000000000000000013255126367015443 5ustar0000000000000000GLUT-2.7.0.16/src/0000755000000000000000000000000012604702100011465 5ustar0000000000000000GLUT-2.7.0.16/src/Graphics/0000755000000000000000000000000012604702100013225 5ustar0000000000000000GLUT-2.7.0.16/src/Graphics/UI/0000755000000000000000000000000013255126367013564 5ustar0000000000000000GLUT-2.7.0.16/src/Graphics/UI/GLUT/0000755000000000000000000000000013350447541014333 5ustar0000000000000000GLUT-2.7.0.16/src/Graphics/UI/GLUT/Callbacks/0000755000000000000000000000000013255126367016216 5ustar0000000000000000GLUT-2.7.0.16/src/Graphics/UI/GLUT/Raw/0000755000000000000000000000000013255126367015070 5ustar0000000000000000GLUT-2.7.0.16/src/Graphics/UI/GLUT.hs0000644000000000000000000004213213255126367014675 0ustar0000000000000000----------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- A Haskell binding for GLUT, the OpenGL Utility Toolkit, a window system -- independent toolkit for writing OpenGL programs. It includes support for -- the extended functionality available in freeglut (see -- ) and OpenGLUT (see -- ), too. -- ----------------------------------------------------------------------------- module Graphics.UI.GLUT ( -- * Legal stuff -- $LegalStuff -- * Introduction -- $Introduction -- ** Background -- $Background -- ** Design Philosophy -- $DesignPhilosophy -- ** API Versions -- $APIVersions -- ** Conventions -- $Conventions -- ** Terminology -- $Terminology module Graphics.Rendering.OpenGL, module Graphics.UI.GLUT.Initialization, module Graphics.UI.GLUT.Begin, module Graphics.UI.GLUT.Window, module Graphics.UI.GLUT.Overlay, module Graphics.UI.GLUT.Menu, module Graphics.UI.GLUT.Callbacks, module Graphics.UI.GLUT.Colormap, module Graphics.UI.GLUT.State, module Graphics.UI.GLUT.Fonts, module Graphics.UI.GLUT.Objects, module Graphics.UI.GLUT.Debugging, module Graphics.UI.GLUT.DeviceControl, module Graphics.UI.GLUT.GameMode ) where import Graphics.Rendering.OpenGL import Graphics.UI.GLUT.Initialization import Graphics.UI.GLUT.Begin import Graphics.UI.GLUT.Window import Graphics.UI.GLUT.Overlay import Graphics.UI.GLUT.Menu import Graphics.UI.GLUT.Callbacks import Graphics.UI.GLUT.Colormap import Graphics.UI.GLUT.State import Graphics.UI.GLUT.Fonts import Graphics.UI.GLUT.Objects import Graphics.UI.GLUT.Debugging import Graphics.UI.GLUT.DeviceControl import Graphics.UI.GLUT.GameMode ----------------------------------------------------------------------------- -- $LegalStuff -- This documentation is heavily based on the man pages of Mark J. Kilgard\'s -- GLUT library. -- -- OpenGL is a trademark of Silicon Graphics, Inc. -- X Window System is a trademark of X Consortium, Inc. -- Spaceball is a registered trademark of Spatial Systems, Inc. -- -- The author has taken care in preparation of this documentation but makes -- no expressed or implied warranty of any kind and assumes no responsibility -- for errors or omissions. No liability is assumed for incidental or -- consequential damages in connection with or arising from the use of -- information or programs contained herein. ----------------------------------------------------------------------------- -- $Introduction -- The OpenGL Utility Toolkit (GLUT) is a programming interface for writing -- window system independent OpenGL programs. Currently there are -- implementations for the X Window System, the Windows family, OS\/2, and Mac. -- The toolkit supports the following functionality: -- -- * Multiple windows for OpenGL rendering. -- -- * Callback driven event processing. -- -- * Sophisticated input devices. -- -- * An /idle/ routine and timers. -- -- * A simple, cascading pop-up menu facility. -- -- * Utility routines to generate various solid and wire frame objects. -- -- * Support for bitmap and stroke fonts. -- -- * Miscellaneous window management functions, including managing overlays. -- -- This documentation serves as both a specification and a programming guide. -- If you are interested in a brief introduction to programming with GLUT, -- have a look at the relevant parts of and the vast -- amount of books on OpenGL, most of them use GLUT. -- -- The remainder of this section describes GLUT\'s design philosophy and -- usage model. The following sections specify the GLUT routines, grouped by -- functionality. The final sections discuss usage advice and the logical -- programmer visible state maintained by GLUT. ----------------------------------------------------------------------------- -- $Background -- One of the major accomplishments in the specification of OpenGL was -- the isolation of window system dependencies from OpenGL\'s rendering -- model. The result is that OpenGL is window system independent. -- -- Window system operations such as the creation of a rendering window and the -- handling of window system events are left to the native window system to -- define. Necessary interactions between OpenGL and the window system such as -- creating and binding an OpenGL context to a window are described separately -- from the OpenGL specification in a window system dependent specification. For -- example, the GLX specification describes the standard by which OpenGL -- interacts with the X Window System. -- -- The predecessor to OpenGL is IRIS GL. Unlike OpenGL, IRIS GL /does/ -- specify how rendering windows are created and manipulated. IRIS GL\'s -- windowing interface is reasonably popular largely because it is simple to -- use. IRIS GL programmers can worry about graphics programming without needing -- to be an expert in programming the native window system. Experience also -- demonstrated that IRIS GL\'s windowing interface was high-level enough that -- it could be retargeted to different window systems. Silicon Graphics migrated -- from NeWS to the X Window System without any major changes to IRIS GL\'s -- basic windowing interface. -- -- Removing window system operations from OpenGL is a sound decision because it -- allows the OpenGL graphics system to be retargeted to various systems -- including powerful but expensive graphics workstations as well as -- mass-production graphics systems like video games, set-top boxes for -- interactive television, and PCs. -- -- Unfortunately, the lack of a window system interface for OpenGL is a gap in -- OpenGL\'s utility. Learning native window system APIs such as the X Window -- System\'s Xlib or Motif can be daunting. Even those familiar with -- native window system APIs need to understand the interface that binds OpenGL -- to the native window system. And when an OpenGL program is written using the -- native window system interface, despite the portability of the program\'s -- OpenGL rendering code, the program itself will be window system dependent. -- -- Testing and documenting OpenGL\'s functionality lead to the development of -- the @tk@ and @aux@ toolkits. The @aux@ toolkit is used in the examples found -- in the /OpenGL Programming Guide/. Unfortunately, @aux@ has numerous -- limitations and its utility is largely limited to toy programs. The @tk@ -- library has more functionality than @aux@ but was developed in an /ad hoc/ -- fashion and still lacks much important functionality that IRIS GL programmers -- expect, like pop-up menus and overlays. -- -- GLUT is designed to fill the need for a window system independent programming -- interface for OpenGL programs. The interface is designed to be simple yet -- still meet the needs of useful OpenGL programs. Features from the IRIS GL, -- @aux@, and @tk@ interfaces are included to make it easy for programmers used -- to these interfaces to develop programs for GLUT. ----------------------------------------------------------------------------- -- $DesignPhilosophy -- GLUT simplifies the implementation of programs using OpenGL rendering. The -- GLUT application programming interface (API) requires very few routines to -- display a graphics scene rendered using OpenGL. The GLUT API (like the OpenGL -- API) is stateful. Most initial GLUT state is defined and the initial state is -- reasonable for simple programs. The GLUT routines also take relatively few -- parameters. -- -- The GLUT API is (as much as reasonable) window system independent. For this -- reason, GLUT does not return /any/ native window system handles, pointers, or -- other data structures. More subtle window system dependencies such as -- reliance on window system dependent fonts are avoided by GLUT; instead, GLUT -- supplies its own (limited) set of fonts. -- -- For programming ease, GLUT provides a simple menu sub-API. While the menuing -- support is designed to be implemented as pop-up menus, GLUT gives window -- system leeway to support the menu functionality in another manner (pull-down -- menus for example). -- -- Two of the most important pieces of GLUT state are the /current window/ and -- /current menu/. Most window and menu routines affect the /current window/ or -- /menu/ respectively. Most callbacks implicitly set the /current window/ and -- /menu/ to the appropriate window or menu responsible for the callback. GLUT -- is designed so that a program with only a single window and\/or menu will not -- need to keep track of any window or menu identifiers. This greatly simplifies -- very simple GLUT programs. -- -- GLUT is designed for simple to moderately complex programs focused on OpenGL -- rendering. GLUT implements its own event loop. For this reason, mixing GLUT -- with other APIs that demand their own event handling structure may be -- difficult. The advantage of a builtin event dispatch loop is simplicity. -- -- GLUT contains routines for rendering fonts and geometric objects, however -- GLUT makes no claims on the OpenGL display list name space. For this reason, -- none of the GLUT rendering routines use OpenGL display lists. It is up to the -- GLUT programmer to compile the output from GLUT rendering routines into -- display lists if this is desired. -- -- GLUT routines are logically organized into several sub-APIs according to -- their functionality. The sub-APIs are: -- -- * /Initialization:/ Command line processing, window system initialization, -- and initial window creation state are controlled by these routines. -- -- * /Beginning Event Processing:/ This routine enters GLUT\'s event processing -- loop. This routine never returns, and it continuously calls GLUT callbacks -- as necessary. -- -- * /Window Management:/ These routines create and control windows. -- -- * /Overlay Management:/ These routines establish and manage overlays for -- windows. -- -- * /Menu Management:/ These routines create and control pop-up menus. -- -- * /Callback Registration:/ These routines register callbacks to be called by -- the GLUT event processing loop. -- -- * /Color Index Colormap Management:/ These routines allow the manipulation -- of color index colormaps for windows. -- -- * /State Retrieval:/ These routines allows programs to retrieve state from -- GLUT. -- -- * /Font Rendering:/ These routines allow rendering of stroke and bitmap -- fonts. -- -- * /Geometric Shape Rendering:/ These routines allow the rendering of 3D -- geometric objects including spheres, cones, icosahedrons, and teapots. -- -- * /Debugging:/ This routine reports any pending GL errors. -- -- * /Device Control:/ These routines allow setting the key repeat and polling -- the joystick. -- -- * /Game Mode:/ These routines allow programs to enter\/leave a full-screen -- mode with specified properties. -- Note that the following item has been left out intentionally, its -- implementation is too SGI-specific: -- * /Video Resizing:/ These routines provide a means for doing swap or frame -- synchronous resizing\/panning of the area that is to be magnified (or -- passed through) to the output video resolution. ----------------------------------------------------------------------------- -- $APIVersions -- The GLUT API has undergone several revisions with increasing functionality. -- This Haskell binding provides access to everything in API version 4, -- although it is not yet officially finalized. Nevertheless, it provides very -- useful things like handling full-screen modes and special keys. ----------------------------------------------------------------------------- -- $Conventions -- GLUT window and screen coordinates are expressed in pixels. The upper -- left hand corner of the screen or a window is (0,0). X coordinates -- increase in a rightward direction; Y coordinates increase in a -- downward direction. Note: This is inconsistent with OpenGL\'s -- coordinate scheme that generally considers the lower left hand -- coordinate of a window to be at (0,0) but is consistent with most -- popular window systems. ----------------------------------------------------------------------------- -- $Terminology -- A number of terms are used in a GLUT-specific manner throughout this -- document. The GLUT meaning of these terms is independent of the window -- system GLUT is used with. Here are GLUT-specific meanings for the -- following GLUT-specific terms: -- -- * /Callback:/ A programmer specified routine that can be registered with -- GLUT to be called in response to a specific type of event. Also used to -- refer to a specific callback routine being called. -- -- * /Colormap:/ A mapping of pixel values to RGB color values. Used by color -- index windows. -- -- * /Dials and button box:/ A sophisticated input device consisting of a pad -- of buttons and an array of rotating dials, often used by computer-aided -- design programs. -- -- * /Display mode:/ A set of OpenGL frame buffer capabilities that can be -- attributed to a window. -- -- * /Idle:/ A state when no window system events are received for processing -- as callbacks and the idle callback, if one is registered, is called. -- -- * /Layer in use:/ Either the normal plane or overlay. This per-window state -- determines what frame buffer layer OpenGL commands affect. -- -- * /Menu entry:/ A menu item that the user can select to trigger the menu -- callback for the menu entry\'s value. -- -- * /Menu item:/ Either a menu entry or a sub-menu trigger. -- -- * /Modifiers:/ The Shift, Ctrl, and Alt keys that can be held down -- simultaneously with a key or mouse button being pressed or released. -- -- * /Multisampling:/ A technique for hardware antialiasing generally available -- only on expensive 3D graphics hardware. Each pixel is composed of a number -- of samples (each containing color and depth information). The samples are -- averaged to determine the displayed pixel color value. Multisampling is -- supported as an extension to OpenGL. -- -- * /Normal plane:/ The default frame buffer layer where GLUT window state -- resides; as opposed to the /overlay/. -- -- * /Overlay:/ A frame buffer layer that can be displayed preferentially to -- the /normal plane/ and supports transparency to display through to the -- /normal plane/. Overlays are useful for rubber-banding effects, text -- annotation, and other operations, to avoid damaging the normal plane frame -- buffer state. Overlays require hardware support not present on all systems. -- -- * /Pop:/ The act of forcing a window to the top of the stacking order for -- sibling windows. -- -- * /Pop-up menu:/ A menu that can be set to appear when a specified mouse -- button is pressed in a window. A pop-menu consists of multiple menu items. -- -- * /Push:/ The act of forcing a window to the bottom of the stacking order -- for sibling windows. -- -- * /Reshape:/ The act of changing the size or shape of the window. -- -- * /Spaceball:/ A sophisticated 3D input device that provides six degrees of -- freedom, three axes of rotation and three axes of translation. It also -- supports a number of buttons. The device is a hand-sized ball attached to -- a base. By cupping the ball with one\'s hand and applying torsional or -- directional force on the ball, rotations and translationsare generated. -- -- * /Stereo:/ A frame buffer capability providing left and right color buffers -- for creating stereoscopic renderings. Typically, the user wears LCD -- shuttered goggles synchronized with the alternating display on the screen -- of the left and right color buffers. -- -- * /Sub-menu:/ A menu cascaded from some sub-menu trigger. -- -- * /Sub-menu trigger:/ A menu item that the user can enter to cascade another -- pop-up menu. -- -- * /Subwindow:/ A type of window that is the child window of a top-level -- window or other subwindow. The drawing and visible region of a subwindow -- is limited by its parent window. -- -- * /Tablet:/ A precise 2D input device. Like a mouse, 2D coordinates are -- returned. The absolute position of the tablet \"puck\" on the tablet is -- returned. Tablets also support a number of buttons. -- -- * /Timer:/ A callback that can be scheduled to be called in a specified -- interval of time. -- -- * /Top-level window:/ A window that can be placed, moved, resized, etc. -- independently from other top-level windows by the user. Subwindows may -- reside within a top-level window. -- -- * /Window:/ A rectangular area for OpenGL rendering. -- -- * /Window display state:/ One of shown, hidden, or iconified. A shown window -- is potentially visible on the screen (it may be obscured by other windows -- and not actually visible). A hidden window will never be visible. An -- iconified window is not visible but could be made visible in response to -- some user action like clicking on the window\'s corresponding icon. -- -- * /Window system:/ A broad notion that refers to both the mechanism and -- policy of the window system. For example, in the X Window System both the -- window manager and the X server are integral to what GLUT considers the -- window system. GLUT-2.7.0.16/src/Graphics/UI/GLUT/Begin.hs0000644000000000000000000000732013255126367015721 0ustar0000000000000000-------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Begin -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- After a GLUT program has done initial setup such as creating windows and -- menus, GLUT programs enter the GLUT event processing loop by calling -- 'mainLoop' or handle events iteratively with 'mainLoopEvent'. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Begin ( -- * Handling events mainLoop, mainLoopEvent, leaveMainLoop, -- * Controlling the behaviour when windows are closed ActionOnWindowClose(..), actionOnWindowClose ) where import Control.Monad.IO.Class ( MonadIO(..) ) import Data.StateVar ( StateVar, makeStateVar ) import Foreign.C.Types ( CInt ) import Graphics.UI.GLUT.QueryUtils import Graphics.UI.GLUT.Raw -------------------------------------------------------------------------------- -- | Enter the GLUT event processing loop; it will call as necessary any -- callbacks that have been registered. This routine should be called at most -- once in a GLUT program. mainLoop :: MonadIO m => m () mainLoop = glutMainLoop -------------------------------------------------------------------------------- -- | (/freeglut only/) Process one iteration's worth of events in its event loop. -- This allows the application to control its own event loop and still use the -- GLUT package. mainLoopEvent :: MonadIO m => m () mainLoopEvent = glutMainLoopEvent -------------------------------------------------------------------------------- -- | (/freeglut only/) Stop the event loop. If 'actionOnWindowClose' contains -- 'Exit', the application will exit; otherwise control will return to the -- function which called 'mainLoop'. -- -- If the application has two nested calls to 'mainLoop' and calls -- 'leaveMainLoop', the behaviour is undefined. It may leave only the inner -- nested loop or it may leave both loops. If the reader has a strong preference -- for one behaviour over the other he should contact the freeglut Programming -- Consortium and ask for the code to be fixed. leaveMainLoop :: MonadIO m => m () leaveMainLoop = glutLeaveMainLoop -------------------------------------------------------------------------------- -- | The behaviour when the user closes a window. data ActionOnWindowClose = -- | Exit the whole program when any window is closed or 'leaveMainLoop' -- is called (default). Exit | -- | Return from mainLoop when any window is closed. MainLoopReturns | -- | Return from mainLoop after the last window is closed. ContinueExecution deriving ( Eq, Ord, Show ) marshalActionOnWindowClose :: ActionOnWindowClose -> CInt marshalActionOnWindowClose x = case x of Exit -> glut_ACTION_EXIT MainLoopReturns -> glut_ACTION_GLUTMAINLOOP_RETURNS ContinueExecution -> glut_ACTION_CONTINUE_EXECUTION unmarshalActionOnWindowClose :: CInt -> ActionOnWindowClose unmarshalActionOnWindowClose x | x == glut_ACTION_EXIT = Exit | x == glut_ACTION_GLUTMAINLOOP_RETURNS = MainLoopReturns | x == glut_ACTION_CONTINUE_EXECUTION = ContinueExecution | otherwise = error ("unmarshalActionOnWindowClose: illegal value " ++ show x) ----------------------------------------------------------------------------- -- | (/freeglut only/) Controls the behaviour when the user closes a window. actionOnWindowClose :: StateVar ActionOnWindowClose actionOnWindowClose = makeStateVar (simpleGet unmarshalActionOnWindowClose glut_ACTION_ON_WINDOW_CLOSE) (glutSetOption glut_ACTION_ON_WINDOW_CLOSE . marshalActionOnWindowClose) GLUT-2.7.0.16/src/Graphics/UI/GLUT/Callbacks.hs0000644000000000000000000000424513255126367016557 0ustar0000000000000000-------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Callbacks -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- -- GLUT supports a number of callbacks to respond to events. There are three -- types of callbacks: window, menu, and global. Window callbacks indicate when -- to redisplay or reshape a window, when the visibility of the window changes, -- and when input is available for the window. Menu callbacks are described in -- "Graphics.UI.GLUT.Menu". The global callbacks manage the passing of time and -- menu usage. The calling order of callbacks between different windows is -- undefined. -- -- Callbacks for input events should be delivered to the window the event occurs -- in. Events should not propagate to parent windows. -- -- A callback of type @Foo@ can registered by setting @fooCallback@ to 'Just' -- the callback. Almost all callbacks can be de-registered by setting -- the corresponding @fooCallback@ to 'Nothing', the only exceptions being -- 'Graphics.UI.GLUT.Callbacks.Window.DisplayCallback' (can only be -- re-registered) and 'Graphics.UI.GLUT.Callbacks.Global.TimerCallback' (can\'t -- be unregistered). -- -- /X Implementation Notes:/ The X GLUT implementation uses the X Input -- extension to support sophisticated input devices: Spaceball, dial & button -- box, and digitizing tablet. Because the X Input extension does not mandate -- how particular types of devices are advertised through the extension, it is -- possible GLUT for X may not correctly support input devices that would -- otherwise be of the correct type. The X GLUT implementation will support the -- Silicon Graphics Spaceball, dial & button box, and digitizing tablet as -- advertised through the X Input extension. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Callbacks ( module Graphics.UI.GLUT.Callbacks.Window, module Graphics.UI.GLUT.Callbacks.Global ) where import Graphics.UI.GLUT.Callbacks.Window import Graphics.UI.GLUT.Callbacks.Global GLUT-2.7.0.16/src/Graphics/UI/GLUT/Callbacks/Global.hs0000644000000000000000000001130213255126367017747 0ustar0000000000000000-------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Callbacks.Global -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Callbacks.Global ( -- * Menu status callback MenuUsage(..), MenuStatusCallback, menuStatusCallback, -- * Idle callback IdleCallback, idleCallback, -- * Timer callbacks Timeout, TimerCallback, addTimerCallback ) where import Control.Monad.Fix ( mfix ) import Data.StateVar ( SettableStateVar, makeSettableStateVar ) import Foreign.C.Types ( CInt ) import Graphics.Rendering.OpenGL ( Position(..) ) import Graphics.UI.GLUT.Callbacks.Registration import Graphics.UI.GLUT.Raw -------------------------------------------------------------------------------- data MenuUsage = NotInUse | InUse deriving ( Eq, Ord, Show ) unmarshalMenuUsage :: CInt -> MenuUsage unmarshalMenuUsage x | x == glut_MENU_NOT_IN_USE = NotInUse | x == glut_MENU_IN_USE = InUse | otherwise = error ("unmarshalMenuUsage: illegal value " ++ show x) type MenuStatusCallback = MenuUsage -> Position -> IO () -- | Controls the global menu status callback so a GLUT program can determine -- when a menu is in use or not. When a menu status callback is registered, it -- will be called with the value 'InUse' when pop-up menus are in use by the -- user; and the callback will be called with the value 'NotInUse' when pop-up -- menus are no longer in use. Additionally, the location in window coordinates -- of the button press that caused the menu to go into use, or the location where -- the menu was released (maybe outside the window). Other callbacks continue to -- operate (except mouse motion callbacks) when pop-up menus are in use so the -- menu status callback allows a program to suspend animation or other tasks -- when menus are in use. The cascading and unmapping of sub-menus from an -- initial pop-up menu does not generate menu status callbacks. There is a -- single menu status callback for GLUT. -- -- When the menu status callback is called, the /current menu/ will be set to -- the initial pop-up menu in both the 'InUse' and 'NotInUse' cases. The -- /current window/ will be set to the window from which the initial menu was -- popped up from, also in both cases. menuStatusCallback :: SettableStateVar (Maybe MenuStatusCallback) menuStatusCallback = makeSettableStateVar $ setCallback MenuStatusCB glutMenuStatusFunc (makeMenuStatusFunc . unmarshal) where unmarshal cb s x y = cb (unmarshalMenuUsage s) (Position (fromIntegral x) (fromIntegral y)) -------------------------------------------------------------------------------- type IdleCallback = IO () -- | Controls the global idle callback so a GLUT program can perform background -- processing tasks or continuous animation when window system events are not -- being received. If enabled, the idle callback is continuously called when -- events are not being received. The /current window/ and /current menu/ will -- not be changed before the idle callback. Programs with multiple windows -- and\/or menus should explicitly set the /current window/ and\/or /current -- menu/ and not rely on its current setting. -- -- The amount of computation and rendering done in an idle callback should be -- minimized to avoid affecting the program\'s interactive response. In general, -- not more than a single frame of rendering should be done in an idle callback. idleCallback :: SettableStateVar (Maybe IdleCallback) idleCallback = makeSettableStateVar $ setCallback IdleCB glutIdleFunc makeIdleFunc -------------------------------------------------------------------------------- -- | Timeout for the timer callback in milliseconds type Timeout = Int type TimerCallback = IO () -- | Register a one-shot timer callback to be triggered after at least the given -- amount of time. Multiple timer callbacks at same or differing times may be -- registered simultaneously. There is no support for canceling a registered -- callback. -- -- The number of milliseconds is a lower bound on the time before the callback -- is generated. GLUT attempts to deliver the timer callback as soon as possible -- after the expiration of the callback\'s time interval. addTimerCallback :: Timeout -> TimerCallback -> IO () addTimerCallback msecs timerCallback = do funPtr <- mfix (\self -> makeTimerFunc (\_ -> do registerForCleanup self timerCallback)) glutTimerFunc (fromIntegral msecs) funPtr 0 GLUT-2.7.0.16/src/Graphics/UI/GLUT/Callbacks/Window.hs0000644000000000000000000011516313255126367020030 0ustar0000000000000000-------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Callbacks.Window -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Callbacks.Window ( -- * Redisplay callbacks DisplayCallback, displayCallback, overlayDisplayCallback, -- * Reshape callback ReshapeCallback, reshapeCallback, -- * Position callback PositionCallback, positionCallback, -- * Callbacks for visibility changes Visibility(..), VisibilityCallback, visibilityCallback, WindowState(..), WindowStateCallback, windowStateCallback, -- * Window close callback CloseCallback, closeCallback, -- * Life cycle callbacks for mobile platforms InitContextCallback, initContextCallback, AppStatus(..), AppStatusCallback, appStatusCallback, -- * Keyboard callback KeyboardCallback, keyboardCallback, keyboardUpCallback, -- * Special callback SpecialCallback, specialCallback, specialUpCallback, -- * Mouse callback MouseCallback, mouseCallback, -- * Keyboard and mouse input callback Key(..), SpecialKey(..), MouseButton(..), KeyState(..), Modifiers(..), KeyboardMouseCallback, keyboardMouseCallback, -- * Mouse wheel callback WheelNumber, WheelDirection, MouseWheelCallback, mouseWheelCallback, -- * Mouse movement callbacks MotionCallback, motionCallback, passiveMotionCallback, Crossing(..), CrossingCallback, crossingCallback, -- * Spaceball callback SpaceballMotion, SpaceballRotation, ButtonIndex, SpaceballInput(..), SpaceballCallback, spaceballCallback, -- * Dial & button box callback DialAndButtonBoxInput(..), DialIndex, DialAndButtonBoxCallback, dialAndButtonBoxCallback, -- * Tablet callback TabletPosition(..), TabletInput(..), TabletCallback, tabletCallback, -- * Joystick callback JoystickButtons(..), JoystickPosition(..), JoystickCallback, joystickCallback, -- * Multi-touch support TouchID, MultiMouseCallback, multiMouseCallback, MultiCrossingCallback, multiCrossingCallback, MultiMotionCallback, multiMotionCallback, multiPassiveMotionCallback ) where import Data.Bits ( (.&.) ) import Data.Char ( chr ) import Data.Maybe ( fromJust ) import Data.StateVar ( SettableStateVar, makeSettableStateVar ) import Foreign.C.Types ( CInt, CUInt ) import Graphics.Rendering.OpenGL ( Position(..), Size(..) ) import Graphics.UI.GLUT.Callbacks.Registration import Graphics.UI.GLUT.Raw import Graphics.UI.GLUT.State import Graphics.UI.GLUT.Types -------------------------------------------------------------------------------- -- | A display callback type DisplayCallback = IO () -- | Controls the display callback for the /current window./ When GLUT determines -- that the normal plane for the window needs to be redisplayed, the display -- callback for the window is called. Before the callback, the /current window/ -- is set to the window needing to be redisplayed and (if no overlay display -- callback is registered) the /layer in use/ is set to the normal plane. The -- entire normal plane region should be redisplayed in response to the callback -- (this includes ancillary buffers if your program depends on their state). -- -- GLUT determines when the display callback should be triggered based on the -- window\'s redisplay state. The redisplay state for a window can be either set -- explicitly by calling 'Graphics.UI.GLUT.Window.postRedisplay' or implicitly -- as the result of window damage reported by the window system. Multiple posted -- redisplays for a window are coalesced by GLUT to minimize the number of -- display callbacks called. -- -- When an overlay is established for a window, but there is no overlay display -- callback registered, the display callback is used for redisplaying both the -- overlay and normal plane (that is, it will be called if either the redisplay -- state or overlay redisplay state is set). In this case, the /layer in use/ is -- not implicitly changed on entry to the display callback. -- -- See 'overlayDisplayCallback' to understand how distinct callbacks for the -- overlay and normal plane of a window may be established. -- -- When a window is created, no display callback exists for the window. It is -- the responsibility of the programmer to install a display callback for the -- window before the window is shown. A display callback must be registered for -- any window that is shown. If a window becomes displayed without a display -- callback being registered, a fatal error occurs. There is no way to -- \"deregister\" a display callback (though another callback routine can always -- be registered). -- -- Upon return from the display callback, the normal damaged state of the window -- (see 'Graphics.UI.GLUT.State.damaged') is cleared. If there is no overlay -- display callback registered the overlay damaged state of the window (see -- 'Graphics.UI.GLUT.State.damaged') is also cleared. displayCallback :: SettableStateVar DisplayCallback displayCallback = makeSettableStateVar $ setCallback DisplayCB glutDisplayFunc makeDisplayFunc . Just -------------------------------------------------------------------------------- -- | Controls the overlay display callback for the /current window./ The overlay -- display callback is functionally the same as the window\'s display callback -- except that the overlay display callback is used to redisplay the window\'s -- overlay. -- -- When GLUT determines that the overlay plane for the window needs to be -- redisplayed, the overlay display callback for the window is called. Before -- the callback, the /current window/ is set to the window needing to be -- redisplayed and the /layer in use/ is set to the overlay. The entire overlay -- region should be redisplayed in response to the callback (this includes -- ancillary buffers if your program depends on their state). -- -- GLUT determines when the overlay display callback should be triggered based -- on the window\'s overlay redisplay state. The overlay redisplay state for a -- window can be either set explicitly by calling -- 'Graphics.UI.GLUT.Overlay.postOverlayRedisplay' or implicitly as the result -- of window damage reported by the window system. Multiple posted overlay -- redisplays for a window are coalesced by GLUT to minimize the number of -- overlay display callbacks called. -- -- Upon return from the overlay display callback, the overlay damaged state of -- the window (see 'Graphics.UI.GLUT.State.damaged') is cleared. -- -- Initially there is no overlay display callback registered when an overlay is -- established. See 'displayCallback' to understand how the display callback -- alone is used if an overlay display callback is not registered. overlayDisplayCallback :: SettableStateVar (Maybe DisplayCallback) overlayDisplayCallback = makeSettableStateVar $ setCallback OverlayDisplayCB glutOverlayDisplayFunc makeOverlayDisplayFunc -------------------------------------------------------------------------------- -- | A reshape callback type ReshapeCallback = Size -> IO () -- | Controls the reshape callback for the /current window./ The reshape callback -- is triggered when a window is reshaped. A reshape callback is also triggered -- immediately before a window\'s first display callback after a window is -- created or whenever an overlay for the window is established. The parameter -- of the callback specifies the new window size in pixels. Before the callback, -- the /current window/ is set to the window that has been reshaped. -- -- If a reshape callback is not registered for a window or 'reshapeCallback' is -- set to 'Nothing' (to deregister a previously registered callback), the -- default reshape callback is used. This default callback will simply call -- -- @ -- 'Graphics.Rendering.OpenGL.GL.CoordTrans.viewport' ('Graphics.Rendering.OpenGL.GL.CoordTrans.Position' 0 0) ('Graphics.Rendering.OpenGL.GL.CoordTrans.Size' /width/ /height/) -- @ -- -- on the normal plane (and on the overlay if one exists). -- -- If an overlay is established for the window, a single reshape callback is -- generated. It is the callback\'s responsibility to update both the normal -- plane and overlay for the window (changing the layer in use as necessary). -- -- When a top-level window is reshaped, subwindows are not reshaped. It is up to -- the GLUT program to manage the size and positions of subwindows within a -- top-level window. Still, reshape callbacks will be triggered for subwindows -- when their size is changed using 'Graphics.UI.GLUT.Window.windowSize'. reshapeCallback :: SettableStateVar (Maybe ReshapeCallback) reshapeCallback = makeSettableStateVar $ setCallback ReshapeCB glutReshapeFunc (makeReshapeFunc . unmarshal) where unmarshal cb w h = cb (Size (fromIntegral w) (fromIntegral h)) -------------------------------------------------------------------------------- -- | A position callback type PositionCallback = Position -> IO () -- | (/freeglut only/) Controls the position callback for the /current window./ -- The position callback for a window is called when the position of a window -- changes. positionCallback :: SettableStateVar (Maybe PositionCallback) positionCallback = makeSettableStateVar $ setCallback PositionCB glutPositionFunc (makePositionFunc . unmarshal) where unmarshal cb x y = cb (Position (fromIntegral x) (fromIntegral y)) -------------------------------------------------------------------------------- -- | The visibility state of the /current window/ data Visibility = NotVisible -- ^ No part of the /current window/ is visible, i.e., until the -- window\'s visibility changes, all further rendering to the -- window is discarded. | Visible -- ^ The /current window/ is totally or partially visible. GLUT -- considers a window visible if any pixel of the window is -- visible or any pixel of any descendant window is visible on -- the screen. deriving ( Eq, Ord, Show ) unmarshalVisibility :: CInt -> Visibility unmarshalVisibility x | x == glut_NOT_VISIBLE = NotVisible | x == glut_VISIBLE = Visible | otherwise = error ("unmarshalVisibility: illegal value " ++ show x) -------------------------------------------------------------------------------- -- | A visibility callback type VisibilityCallback = Visibility -> IO () -- | Controls the visibility callback for the /current window./ The visibility -- callback for a window is called when the visibility of a window changes. -- -- If the visibility callback for a window is disabled and later re-enabled, the -- visibility status of the window is undefined; any change in window visibility -- will be reported, that is if you disable a visibility callback and re-enable -- the callback, you are guaranteed the next visibility change will be reported. -- -- Note that you can either use 'visibilityCallback' or 'windowStateCallback', -- but not both, because the former is implemented via the latter. visibilityCallback :: SettableStateVar (Maybe VisibilityCallback) visibilityCallback = makeSettableStateVar $ setCallback VisibilityCB glutVisibilityFunc (makeVisibilityFunc . unmarshal) where unmarshal cb = cb . unmarshalVisibility -------------------------------------------------------------------------------- -- | The window state of the /current window/ data WindowState = Unmapped -- ^ The /current window/ is unmapped. | FullyRetained -- ^ The /current window/ is unobscured. | PartiallyRetained -- ^ The /current window/ is partially obscured. | FullyCovered -- ^ The /current window/ is fully obscured. deriving ( Eq, Ord, Show ) unmarshalWindowState :: CInt -> WindowState unmarshalWindowState x | x == glut_HIDDEN = Unmapped | x == glut_FULLY_RETAINED = FullyRetained | x == glut_PARTIALLY_RETAINED = PartiallyRetained | x == glut_FULLY_COVERED = FullyCovered | otherwise = error ("unmarshalWindowState: illegal value " ++ show x) -------------------------------------------------------------------------------- -- | A window state callback type WindowStateCallback = WindowState -> IO () -- | Controls the window state callback for the -- /current window./ The window state callback for a window is called when the -- window state of a window changes. -- -- If the window state callback for a window is disabled and later re-enabled, -- the window state state of the window is undefined; any change in the window -- state will be reported, that is if you disable a window state callback and -- re-enable the callback, you are guaranteed the next window state change will -- be reported. -- -- Note that you can either use 'visibilityCallback' or 'windowStateCallback', -- but not both, because the former is implemented via the latter. windowStateCallback :: SettableStateVar (Maybe WindowStateCallback) windowStateCallback = makeSettableStateVar $ setCallback WindowStatusCB glutWindowStatusFunc (makeWindowStatusFunc . unmarshal) where unmarshal cb = cb . unmarshalWindowState -------------------------------------------------------------------------------- -- | A window close callback type CloseCallback = IO () -- | Controls the window close callback for the /current window/. closeCallback :: SettableStateVar (Maybe CloseCallback) closeCallback = makeSettableStateVar $ setCallback CloseCB glutCloseFunc makeCloseFunc -------------------------------------------------------------------------------- -- | An initialize context callback type InitContextCallback = IO () -- | (/freeglut only/) Controls the initialize context callback for the /current -- window/. initContextCallback :: SettableStateVar (Maybe InitContextCallback) initContextCallback = makeSettableStateVar $ setCallback InitContextCB glutInitContextFunc makeInitContextFunc -------------------------------------------------------------------------------- -- | The application status of the /current window/ data AppStatus = AppStatusPause | AppStatusResume deriving ( Eq, Ord, Show ) unmarshalAppStatus :: CInt -> AppStatus unmarshalAppStatus x | x == glut_APPSTATUS_PAUSE = AppStatusPause | x == glut_APPSTATUS_RESUME = AppStatusResume | otherwise = error ("unmarshalAppStatus: illegal value " ++ show x) -------------------------------------------------------------------------------- -- | An application status callback type AppStatusCallback = AppStatus -> IO () -- | Controls the application status callback for the /current window./ appStatusCallback :: SettableStateVar (Maybe AppStatusCallback) appStatusCallback = makeSettableStateVar $ setCallback AppStatusCB glutAppStatusFunc (makeAppStatusFunc . unmarshal) where unmarshal cb = cb . unmarshalAppStatus -------------------------------------------------------------------------------- -- | A keyboard callback type KeyboardCallback = Char -> Position -> IO () setKeyboardCallback :: Maybe KeyboardCallback -> IO () setKeyboardCallback = setCallback KeyboardCB glutKeyboardFunc (makeKeyboardFunc . unmarshal) where unmarshal cb c x y = cb (chr (fromIntegral c)) (Position (fromIntegral x) (fromIntegral y)) -- | Controls the keyboard callback for the /current window/. This is -- activated only when a key is pressed. keyboardCallback :: SettableStateVar (Maybe KeyboardCallback) keyboardCallback = makeSettableStateVar setKeyboardCallback -------------------------------------------------------------------------------- setKeyboardUpCallback :: Maybe KeyboardCallback -> IO () setKeyboardUpCallback = setCallback KeyboardUpCB glutKeyboardUpFunc (makeKeyboardUpFunc . unmarshal) where unmarshal cb c x y = cb (chr (fromIntegral c)) (Position (fromIntegral x) (fromIntegral y)) -- | Controls the keyboard callback for the /current window/. This is -- activated only when a key is released. keyboardUpCallback :: SettableStateVar (Maybe KeyboardCallback) keyboardUpCallback = makeSettableStateVar setKeyboardUpCallback -------------------------------------------------------------------------------- -- | Special keys data SpecialKey = KeyF1 | KeyF2 | KeyF3 | KeyF4 | KeyF5 | KeyF6 | KeyF7 | KeyF8 | KeyF9 | KeyF10 | KeyF11 | KeyF12 | KeyLeft | KeyUp | KeyRight | KeyDown | KeyPageUp | KeyPageDown | KeyHome | KeyEnd | KeyInsert | KeyNumLock | KeyBegin | KeyDelete | KeyShiftL | KeyShiftR | KeyCtrlL | KeyCtrlR | KeyAltL | KeyAltR | KeyUnknown Int -- ^ You should actually never encounter this value, it is -- just here as a safeguard against future changes in the -- native GLUT library. deriving ( Eq, Ord, Show ) unmarshalSpecialKey :: CInt -> SpecialKey unmarshalSpecialKey x | x == glut_KEY_F1 = KeyF1 | x == glut_KEY_F2 = KeyF2 | x == glut_KEY_F3 = KeyF3 | x == glut_KEY_F4 = KeyF4 | x == glut_KEY_F5 = KeyF5 | x == glut_KEY_F6 = KeyF6 | x == glut_KEY_F7 = KeyF7 | x == glut_KEY_F8 = KeyF8 | x == glut_KEY_F9 = KeyF9 | x == glut_KEY_F10 = KeyF10 | x == glut_KEY_F11 = KeyF11 | x == glut_KEY_F12 = KeyF12 | x == glut_KEY_LEFT = KeyLeft | x == glut_KEY_UP = KeyUp | x == glut_KEY_RIGHT = KeyRight | x == glut_KEY_DOWN = KeyDown | x == glut_KEY_PAGE_UP = KeyPageUp | x == glut_KEY_PAGE_DOWN = KeyPageDown | x == glut_KEY_HOME = KeyHome | x == glut_KEY_END = KeyEnd | x == glut_KEY_INSERT = KeyInsert | x == glut_KEY_NUM_LOCK = KeyNumLock | x == glut_KEY_BEGIN = KeyBegin | x == glut_KEY_DELETE = KeyDelete | x == glut_KEY_SHIFT_L = KeyShiftL | x == glut_KEY_SHIFT_R = KeyShiftR | x == glut_KEY_CTRL_L = KeyCtrlL | x == glut_KEY_CTRL_R = KeyCtrlR | x == glut_KEY_ALT_L = KeyAltL | x == glut_KEY_ALT_R = KeyAltR | otherwise = KeyUnknown (fromIntegral x) -------------------------------------------------------------------------------- -- | A special key callback type SpecialCallback = SpecialKey -> Position -> IO () setSpecialCallback :: Maybe SpecialCallback -> IO () setSpecialCallback = setCallback SpecialCB glutSpecialFunc (makeSpecialFunc . unmarshal) where unmarshal cb k x y = cb (unmarshalSpecialKey k) (Position (fromIntegral x) (fromIntegral y)) -- | Controls the special key callback for the /current window/. This is -- activated only when a special key is pressed. specialCallback :: SettableStateVar (Maybe SpecialCallback) specialCallback = makeSettableStateVar setSpecialCallback -------------------------------------------------------------------------------- setSpecialUpCallback :: Maybe SpecialCallback -> IO () setSpecialUpCallback = setCallback SpecialUpCB glutSpecialUpFunc (makeSpecialUpFunc . unmarshal) where unmarshal cb k x y = cb (unmarshalSpecialKey k) (Position (fromIntegral x) (fromIntegral y)) -- | Controls the special key callback for the /current window/. This is -- activated only when a special key is released. specialUpCallback :: SettableStateVar (Maybe SpecialCallback) specialUpCallback = makeSettableStateVar setSpecialUpCallback -------------------------------------------------------------------------------- -- | The current state of a key or button data KeyState = Down | Up deriving ( Eq, Ord, Show ) unmarshalKeyState :: CInt -> KeyState unmarshalKeyState x | x == glut_DOWN = Down | x == glut_UP = Up | otherwise = error ("unmarshalKeyState: illegal value " ++ show x) -------------------------------------------------------------------------------- -- | A mouse callback type MouseCallback = MouseButton -> KeyState -> Position -> IO () setMouseCallback :: Maybe MouseCallback -> IO () setMouseCallback = setCallback MouseCB glutMouseFunc (makeMouseFunc . unmarshal) where unmarshal cb b s x y = cb (unmarshalMouseButton b) (unmarshalKeyState s) (Position (fromIntegral x) (fromIntegral y)) -- | Controls the mouse callback for the /current window/. mouseCallback :: SettableStateVar (Maybe MouseCallback) mouseCallback = makeSettableStateVar setMouseCallback -------------------------------------------------------------------------------- -- | The state of the keyboard modifiers data Modifiers = Modifiers { shift, ctrl, alt :: KeyState } deriving ( Eq, Ord, Show ) -- Could use fromBitfield + Enum/Bounded instances + marshalModifier instead... unmarshalModifiers :: CInt -> Modifiers unmarshalModifiers m = Modifiers { shift = if (m .&. glut_ACTIVE_SHIFT) /= 0 then Down else Up, ctrl = if (m .&. glut_ACTIVE_CTRL ) /= 0 then Down else Up, alt = if (m .&. glut_ACTIVE_ALT ) /= 0 then Down else Up } getModifiers :: IO Modifiers getModifiers = fmap unmarshalModifiers glutGetModifiers -------------------------------------------------------------------------------- -- | A generalized view of keys data Key = Char Char | SpecialKey SpecialKey | MouseButton MouseButton deriving ( Eq, Ord, Show ) -- | A keyboard\/mouse callback type KeyboardMouseCallback = Key -> KeyState -> Modifiers -> Position -> IO () -- | Controls the keyboard\/mouse callback for the /current window./ The -- keyboard\/mouse callback for a window is called when the state of a key or -- mouse button changes. The callback parameters indicate the new state of the -- key\/button, the state of the keyboard modifiers, and the mouse location in -- window relative coordinates. -- -- Note that this is a convenience function that should not ordinarily be used -- in conjunction with `keyboardCallback`, `keyboardUpCallback`, -- `specialCallback`, `specialUpCallback`, or `mouseCallback`. keyboardMouseCallback :: SettableStateVar (Maybe KeyboardMouseCallback) keyboardMouseCallback = makeSettableStateVar setKeyboardMouseCallback setKeyboardMouseCallback :: Maybe KeyboardMouseCallback -> IO () setKeyboardMouseCallback Nothing = do setKeyboardCallback Nothing setKeyboardUpCallback Nothing setSpecialCallback Nothing setSpecialUpCallback Nothing setMouseCallback Nothing setKeyboardMouseCallback (Just cb) = do setKeyboardCallback (Just (\c p -> do m <- getModifiers cb (Char c) Down m p)) setKeyboardUpCallback (Just (\c p -> do m <- getModifiers cb (Char c) Up m p)) setSpecialCallback (Just (\s p -> do m <- getModifiers cb (SpecialKey s) Down m p)) setSpecialUpCallback (Just (\s p -> do m <- getModifiers cb (SpecialKey s) Up m p)) setMouseCallback (Just (\b s p -> do m <- getModifiers cb (MouseButton b) s m p)) -------------------------------------------------------------------------------- type WheelNumber = Int type WheelDirection = Int type MouseWheelCallback = WheelNumber -> WheelDirection -> Position -> IO () -- | (/freeglut only/) Controls the mouse wheel callback for the -- /current window./ The mouse wheel callback for a window is called when a -- mouse wheel is used and the wheel number is greater than or equal to -- 'Graphics.UI.GLUT.State.numMouseButtons'. mouseWheelCallback :: SettableStateVar (Maybe MouseWheelCallback) mouseWheelCallback = makeSettableStateVar $ setCallback MouseWheelCB glutMouseWheelFunc (makeMouseWheelFunc . unmarshal) where unmarshal cb n d x y = cb (fromIntegral n) (fromIntegral d) (Position (fromIntegral x) (fromIntegral y)) -------------------------------------------------------------------------------- -- | A motion callback type MotionCallback = Position -> IO () -- | Controls the motion callback for the /current window./ The motion callback -- for a window is called when the mouse moves within the window while one or -- more mouse buttons are pressed. The callback parameter indicates the mouse -- location in window relative coordinates. motionCallback :: SettableStateVar (Maybe MotionCallback) motionCallback = makeSettableStateVar $ setCallback MotionCB glutMotionFunc (makeMotionFunc . unmarshal) where unmarshal cb x y = cb (Position (fromIntegral x) (fromIntegral y)) -------------------------------------------------------------------------------- -- | Controls the passive motion callback for the /current window./ The passive -- motion callback for a window is called when the mouse moves within the window -- while /no/ mouse buttons are pressed. The callback parameter indicates the -- mouse location in window relative coordinates. passiveMotionCallback :: SettableStateVar (Maybe MotionCallback) passiveMotionCallback = makeSettableStateVar $ setCallback PassiveMotionCB glutPassiveMotionFunc (makePassiveMotionFunc . unmarshal) where unmarshal cb x y = cb (Position (fromIntegral x) (fromIntegral y)) -------------------------------------------------------------------------------- -- | The relation between the mouse pointer and the /current window/ has -- changed. data Crossing = WindowLeft -- ^ The mouse pointer has left the /current window./ | WindowEntered -- ^ The mouse pointer has entered the /current window./ deriving ( Eq, Ord, Show ) unmarshalCrossing :: CInt -> Crossing unmarshalCrossing x | x == glut_LEFT = WindowLeft | x == glut_ENTERED = WindowEntered | otherwise = error ("unmarshalCrossing: illegal value " ++ show x) -------------------------------------------------------------------------------- -- | An enter\/leave callback type CrossingCallback = Crossing -> IO () -- | Controls the mouse enter\/leave callback for the /current window./ Note -- that some window systems may not generate accurate enter\/leave callbacks. -- -- /X Implementation Notes:/ An X implementation of GLUT should generate -- accurate enter\/leave callbacks. crossingCallback :: SettableStateVar (Maybe CrossingCallback) crossingCallback = makeSettableStateVar $ setCallback CrossingCB glutEntryFunc (makeEntryFunc . unmarshal) where unmarshal cb = cb . unmarshalCrossing -------------------------------------------------------------------------------- -- | Translation of the Spaceball along one axis, normalized to be in the range -- of -1000 to +1000 inclusive type SpaceballMotion = Int -- | Rotation of the Spaceball along one axis, normalized to be in the range -- of -1800 .. +1800 inclusive type SpaceballRotation = Int -- | The index of a specific buttons of an input device. type ButtonIndex = Int -- | The state of the Spaceball has changed. data SpaceballInput = SpaceballMotion SpaceballMotion SpaceballMotion SpaceballMotion | SpaceballRotation SpaceballRotation SpaceballRotation SpaceballRotation | SpaceballButton ButtonIndex KeyState deriving ( Eq, Ord, Show ) -- | A SpaceballButton callback type SpaceballCallback = SpaceballInput -> IO () -- | Controls the Spaceball callback for the /current window./ The Spaceball -- callback for a window is called when the window has Spaceball input focus -- (normally, when the mouse is in the window) and the user generates Spaceball -- translations, rotations, or button presses. The number of available Spaceball -- buttons can be determined with 'Graphics.UI.GLUT.State.numSpaceballButtons'. -- -- Registering a Spaceball callback when a Spaceball device is not available has -- no effect and is not an error. In this case, no Spaceball callbacks will be -- generated. spaceballCallback :: SettableStateVar (Maybe SpaceballCallback) spaceballCallback = makeSettableStateVar setSpaceballCallback setSpaceballCallback :: Maybe SpaceballCallback -> IO () setSpaceballCallback Nothing = do setSpaceballMotionCallback Nothing setSpaceballRotationCallback Nothing setSpaceballButtonCallback Nothing setSpaceballCallback (Just cb) = do setSpaceballMotionCallback (Just (\x y z -> cb (SpaceballMotion x y z))) setSpaceballRotationCallback (Just (\x y z -> cb (SpaceballRotation x y z))) setSpaceballButtonCallback (Just (\b s -> cb (SpaceballButton b s))) -------------------------------------------------------------------------------- type SpaceballMotionCallback = SpaceballMotion -> SpaceballMotion -> SpaceballMotion -> IO () setSpaceballMotionCallback :: Maybe SpaceballMotionCallback -> IO () setSpaceballMotionCallback = setCallback SpaceballMotionCB glutSpaceballMotionFunc (makeSpaceballMotionFunc . unmarshal) where unmarshal cb x y z = cb (fromIntegral x) (fromIntegral y) (fromIntegral z) -------------------------------------------------------------------------------- type SpaceballRotationCallback = SpaceballRotation -> SpaceballRotation -> SpaceballRotation -> IO () setSpaceballRotationCallback :: Maybe SpaceballRotationCallback -> IO () setSpaceballRotationCallback = setCallback SpaceballRotateCB glutSpaceballRotateFunc (makeSpaceballRotateFunc . unmarshal) where unmarshal cb x y z = cb (fromIntegral x) (fromIntegral y) (fromIntegral z) -------------------------------------------------------------------------------- type SpaceballButtonCallback = ButtonIndex -> KeyState -> IO () setSpaceballButtonCallback :: Maybe SpaceballButtonCallback -> IO () setSpaceballButtonCallback = setCallback SpaceballButtonCB glutSpaceballButtonFunc (makeSpaceballButtonFunc . unmarshal) where unmarshal cb b s = cb (fromIntegral b) (unmarshalKeyState s) -------------------------------------------------------------------------------- -- | The index of a specific dial of a dial and button box. type DialIndex = Int -- | The dial & button box state has changed. data DialAndButtonBoxInput = DialAndButtonBoxButton ButtonIndex KeyState | DialAndButtonBoxDial DialIndex Int deriving ( Eq, Ord, Show ) -- | A dial & button box callback type DialAndButtonBoxCallback = DialAndButtonBoxInput -> IO () -- | Controls the dial & button box callback for the /current window./ The dial -- & button box button callback for a window is called when the window has dial -- & button box input focus (normally, when the mouse is in the window) and the -- user generates dial & button box button presses or dial changes. The number -- of available dial & button box buttons and dials can be determined with -- 'Graphics.UI.GLUT.State.numDialsAndButtons'. -- -- Registering a dial & button box callback when a dial & button box device is -- not available is ineffectual and not an error. In this case, no dial & button -- box button will be generated. dialAndButtonBoxCallback :: SettableStateVar (Maybe DialAndButtonBoxCallback) dialAndButtonBoxCallback = makeSettableStateVar setDialAndButtonBoxCallback setDialAndButtonBoxCallback :: Maybe DialAndButtonBoxCallback -> IO () setDialAndButtonBoxCallback Nothing = do setButtonBoxCallback Nothing setDialsCallback Nothing setDialAndButtonBoxCallback (Just cb) = do setButtonBoxCallback (Just (\b s -> cb (DialAndButtonBoxButton b s))) setDialsCallback (Just (\d x -> cb (DialAndButtonBoxDial d x))) -------------------------------------------------------------------------------- type ButtonBoxCallback = ButtonIndex -> KeyState -> IO () setButtonBoxCallback :: Maybe ButtonBoxCallback -> IO () setButtonBoxCallback = setCallback ButtonBoxCB glutButtonBoxFunc (makeButtonBoxFunc . unmarshal) where unmarshal cb b s = cb (fromIntegral b) (unmarshalKeyState s) -------------------------------------------------------------------------------- type DialsCallback = DialIndex -> Int -> IO () setDialsCallback :: Maybe DialsCallback -> IO () setDialsCallback = setCallback DialsCB glutDialsFunc (makeDialsFunc . unmarshal) where unmarshal cb d x = cb (fromIntegral d) (fromIntegral x) -------------------------------------------------------------------------------- -- | Absolute tablet position, with coordinates normalized to be in the range of -- 0 to 2000 inclusive data TabletPosition = TabletPosition Int Int deriving ( Eq, Ord, Show ) -- | The table state has changed. data TabletInput = TabletMotion | TabletButton ButtonIndex KeyState deriving ( Eq, Ord, Show ) -- | A tablet callback type TabletCallback = TabletInput -> TabletPosition -> IO () -- | Controls the tablet callback for the /current window./ The tablet callback -- for a window is called when the window has tablet input focus (normally, when -- the mouse is in the window) and the user generates tablet motion or button -- presses. The number of available tablet buttons can be determined with -- 'Graphics.UI.GLUT.State.numTabletButtons'. -- -- Registering a tablet callback when a tablet device is not available is -- ineffectual and not an error. In this case, no tablet callbacks will be -- generated. tabletCallback :: SettableStateVar (Maybe TabletCallback) tabletCallback = makeSettableStateVar setTabletCallback setTabletCallback :: Maybe TabletCallback -> IO () setTabletCallback Nothing = do setTabletMotionCallback Nothing setTabletButtonCallback Nothing setTabletCallback (Just cb) = do setTabletMotionCallback (Just (\p -> cb TabletMotion p)) setTabletButtonCallback (Just (\b s p -> cb (TabletButton b s) p)) -------------------------------------------------------------------------------- type TabletMotionCallback = TabletPosition -> IO () setTabletMotionCallback :: Maybe TabletMotionCallback -> IO () setTabletMotionCallback = setCallback TabletMotionCB glutTabletMotionFunc (makeTabletMotionFunc . unmarshal) where unmarshal cb x y = cb (TabletPosition (fromIntegral x) (fromIntegral y)) -------------------------------------------------------------------------------- type TabletButtonCallback = ButtonIndex -> KeyState -> TabletPosition -> IO () setTabletButtonCallback :: Maybe TabletButtonCallback -> IO () setTabletButtonCallback = setCallback TabletButtonCB glutTabletButtonFunc (makeTabletButtonFunc . unmarshal) where unmarshal cb b s x y = cb (fromIntegral b) (unmarshalKeyState s) (TabletPosition (fromIntegral x) (fromIntegral y)) -------------------------------------------------------------------------------- -- | The state of the joystick buttons data JoystickButtons = JoystickButtons { joystickButtonA, joystickButtonB, joystickButtonC, joystickButtonD :: KeyState } deriving ( Eq, Ord, Show ) -- Could use fromBitfield + Enum/Bounded instances + unmarshalJoystickButton -- instead... unmarshalJoystickButtons :: CUInt -> JoystickButtons unmarshalJoystickButtons m = JoystickButtons { joystickButtonA = if (m .&. glut_JOYSTICK_BUTTON_A) /= 0 then Down else Up, joystickButtonB = if (m .&. glut_JOYSTICK_BUTTON_B) /= 0 then Down else Up, joystickButtonC = if (m .&. glut_JOYSTICK_BUTTON_C) /= 0 then Down else Up, joystickButtonD = if (m .&. glut_JOYSTICK_BUTTON_D) /= 0 then Down else Up } -------------------------------------------------------------------------------- -- | Absolute joystick position, with coordinates normalized to be in the range -- of -1000 to 1000 inclusive. The signs of the three axes mean the following: -- -- * negative = left, positive = right -- -- * negative = towards player, positive = away -- -- * if available (e.g. rudder): negative = down, positive = up data JoystickPosition = JoystickPosition Int Int Int deriving ( Eq, Ord, Show ) -------------------------------------------------------------------------------- -- | A joystick callback type JoystickCallback = JoystickButtons -> JoystickPosition -> IO () -- | Controls the joystick callback for the /current window./ The joystick -- callback is called either due to polling of the joystick at the uniform timer -- interval specified (if > 0) or in response to an explicit call of -- 'Graphics.UI.GLUT.DeviceControl.forceJoystickCallback'. -- -- /X Implementation Notes:/ Currently GLUT has no joystick support for X11. -- joystickCallback :: SettableStateVar (Maybe JoystickCallback, PollRate) joystickCallback :: SettableStateVar (Maybe (JoystickCallback, PollRate)) joystickCallback = makeSettableStateVar $ \maybeCBAndRate -> setCallback JoystickCB (\f -> glutJoystickFunc f (fromIntegral (snd (fromJust maybeCBAndRate)))) (makeJoystickFunc . unmarshal) (fmap fst maybeCBAndRate) where unmarshal cb b x y z = cb (unmarshalJoystickButtons b) (JoystickPosition (fromIntegral x) (fromIntegral y) (fromIntegral z)) -------------------------------------------------------------------------------- -- | A description where the multi-touch event is coming from, the freeglut -- specs are very vague about the actual semantics. It contains the device ID -- and\/or the cursor\/finger ID. type TouchID = Int -- | A multi-touch variant of 'MouseCallback'. type MultiMouseCallback = TouchID -> MouseCallback -- | (/freeglut only/) A multi-touch variant of 'mouseCallback'. multiMouseCallback :: SettableStateVar (Maybe MultiMouseCallback) multiMouseCallback = makeSettableStateVar $ setCallback MultiButtonCB glutMultiButtonFunc (makeMultiButtonFunc . unmarshal) where unmarshal cb d x y b s = cb (fromIntegral d) (unmarshalMouseButton b) (unmarshalKeyState s) (Position (fromIntegral x) (fromIntegral y)) -- | A multi-touch variant of 'CrossingCallback'. type MultiCrossingCallback = TouchID -> CrossingCallback -- | (/freeglut only/) A multi-touch variant of 'crossingCallback'. multiCrossingCallback :: SettableStateVar (Maybe MultiCrossingCallback) multiCrossingCallback = makeSettableStateVar $ setCallback MultiEntryCB glutMultiEntryFunc (makeMultiEntryFunc . unmarshal) where unmarshal cb d c = cb (fromIntegral d) (unmarshalCrossing c) -- | A multi-touch variant of 'MotionCallback'. type MultiMotionCallback = TouchID -> MotionCallback -- | (/freeglut only/) A multi-touch variant of 'motionCallback'. multiMotionCallback :: SettableStateVar (Maybe MultiMotionCallback) multiMotionCallback = makeSettableStateVar $ setCallback MultiMotionCB glutMultiMotionFunc (makeMultiMotionFunc . unmarshal) where unmarshal cb d x y = cb (fromIntegral d) (Position (fromIntegral x) (fromIntegral y)) -- | (/freeglut only/) A multi-touch variant of 'passiveMotionCallback'. multiPassiveMotionCallback :: SettableStateVar (Maybe MultiMotionCallback) multiPassiveMotionCallback = makeSettableStateVar $ setCallback MultiPassiveCB glutMultiPassiveFunc (makeMultiPassiveFunc . unmarshal) where unmarshal cb d x y = cb (fromIntegral d) (Position (fromIntegral x) (fromIntegral y)) GLUT-2.7.0.16/src/Graphics/UI/GLUT/Colormap.hs0000644000000000000000000001145713255126367016457 0ustar0000000000000000-------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Colormap -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- OpenGL supports both RGBA and color index rendering. The RGBA mode is -- generally preferable to color index because more OpenGL rendering -- capabilities are available and color index mode requires the loading of -- colormap entries. -- -- The GLUT color index state variables are used to read and write entries in a -- window\'s color index colormap. Every GLUT color index window has its own -- logical color index colormap. The size of a window\'s colormap can be -- determined by reading 'numColorMapEntries'. -- -- GLUT color index windows within a program can attempt to share colormap -- resources by copying a single color index colormap to multiple windows using -- 'copyColormap'. If possible GLUT will attempt to share the actual colormap. -- While copying colormaps using 'copyColormap' can potentially allow sharing of -- physical colormap resources, logically each window has its own colormap. So -- changing a copied colormap of a window will force the duplication of the -- colormap. For this reason, color index programs should generally load a -- single color index colormap, copy it to all color index windows within the -- program, and then not modify any colormap cells. -- -- Use of multiple colormaps is likely to result in colormap installation -- problems where some windows are displayed with an incorrect colormap due to -- limitations on colormap resources. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Colormap ( colorMapEntry, copyColormap, numColorMapEntries, transparentIndex ) where import Control.Monad.IO.Class ( MonadIO(..) ) import Data.StateVar ( GettableStateVar, makeGettableStateVar, StateVar, makeStateVar ) import Foreign.C.Types ( CInt ) import Graphics.Rendering.OpenGL.GL.VertexSpec ( Index1(..), Color3(..) ) import Graphics.Rendering.OpenGL ( GLint, GLfloat ) import Graphics.UI.GLUT.QueryUtils import Graphics.UI.GLUT.Raw import Graphics.UI.GLUT.Types -------------------------------------------------------------------------------- -- | Controls the color index colormap entry of the /current window/\'s logical -- colormap for the /layer in use/. The /layer in use/ of the /current window/ -- should be a color index window. The color index should be zero or greater and -- less than the total number of colormap entries for the window (see -- 'numColorMapEntries') and different from an overlay\'s transparent index (see -- 'transparentIndex'). -- -- If the /layer in use/\'s colormap was copied by reference, setting a colormap -- entry will force the duplication of the colormap. colorMapEntry :: Index1 GLint -> StateVar (Color3 GLfloat) colorMapEntry (Index1 cell) = makeStateVar (getColorMapEntry (fromIntegral cell)) (setColorMapEntry (fromIntegral cell)) setColorMapEntry :: CInt -> Color3 GLfloat -> IO () setColorMapEntry cell (Color3 r g b) = glutSetColor cell r g b getColorMapEntry :: CInt -> IO (Color3 GLfloat) getColorMapEntry cell = do r <- glutGetColor cell glut_RED g <- glutGetColor cell glut_GREEN b <- glutGetColor cell glut_BLUE return $ Color3 r g b -------------------------------------------------------------------------------- -- | Copy (lazily if possible to promote sharing) the logical colormap from a -- specified window to the /current window/\'s /layer in use/. The copy will be -- from the normal plane to the normal plane; or from the overlay to the overlay -- (never across different layers). Once a colormap has been copied, avoid -- setting cells in the colormap via 'colorMapEntry' since that will force an -- actual copy of the colormap if it was previously copied by reference. -- 'copyColormap' should only be called when both the /current window/ and the -- specified window are color index windows. copyColormap :: MonadIO m => Window -> m () copyColormap (Window win) = glutCopyColormap win -------------------------------------------------------------------------------- -- | Contains the number of entries in the colormap of the /current window/\'s -- current layer (0 in RGBA mode). numColorMapEntries :: GettableStateVar GLint numColorMapEntries = makeGettableStateVar $ simpleGet fromIntegral glut_WINDOW_COLORMAP_SIZE -------------------------------------------------------------------------------- -- | Contains the transparent color index of the overlay of the /current window/ -- or -1 if no overlay is in use. transparentIndex :: GettableStateVar (Index1 GLint) transparentIndex = makeGettableStateVar $ layerGet (Index1 . fromIntegral) glut_TRANSPARENT_INDEX GLUT-2.7.0.16/src/Graphics/UI/GLUT/Debugging.hs0000644000000000000000000000247613255126367016577 0ustar0000000000000000-------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Debugging -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- This module contains a simple utility routine to report any pending GL -- errors. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Debugging ( reportErrors ) where import Control.Monad.IO.Class ( MonadIO(..) ) import Data.StateVar ( get ) import Graphics.Rendering.OpenGL ( Error(..), errors ) import System.Environment ( getProgName ) import System.IO ( hPutStrLn, stderr ) -------------------------------------------------------------------------------- -- | Report any pending GL errors to stderr (which is typically the console). -- If there are no pending errors, this routine does nothing. Note that the -- error flags are reset after this action, i.e. there are no pending errors -- left afterwards. reportErrors :: MonadIO m => m () reportErrors = get errors >>= mapM_ reportError reportError :: MonadIO m => Error -> m () reportError (Error _ msg) = liftIO $ do pn <- getProgName hPutStrLn stderr ("GLUT: Warning in " ++ pn ++ ": GL error: " ++ msg) GLUT-2.7.0.16/src/Graphics/UI/GLUT/DeviceControl.hs0000644000000000000000000001173713255126367017444 0ustar0000000000000000-------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.DeviceControl -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- GLUT offers some routines for controlling the key repeat and polling the -- joystick. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.DeviceControl ( GlobalKeyRepeat(..), globalKeyRepeat, PerWindowKeyRepeat(..), perWindowKeyRepeat, forceJoystickCallback ) where import Control.Monad.IO.Class ( MonadIO(..) ) import Data.StateVar ( StateVar, makeStateVar ) import Foreign.C.Types ( CInt ) import Graphics.UI.GLUT.QueryUtils import Graphics.UI.GLUT.Raw -------------------------------------------------------------------------------- -- | The state of the global key repeat data GlobalKeyRepeat = GlobalKeyRepeatOff | GlobalKeyRepeatOn | GlobalKeyRepeatDefault deriving ( Eq, Ord, Show ) marshalGlobalKeyRepeat :: GlobalKeyRepeat -> CInt marshalGlobalKeyRepeat x = case x of GlobalKeyRepeatOff -> glut_KEY_REPEAT_OFF GlobalKeyRepeatOn -> glut_KEY_REPEAT_ON GlobalKeyRepeatDefault -> glut_KEY_REPEAT_DEFAULT unmarshalGlobalKeyRepeat :: CInt -> GlobalKeyRepeat unmarshalGlobalKeyRepeat x | x == glut_KEY_REPEAT_OFF = GlobalKeyRepeatOff | x == glut_KEY_REPEAT_ON = GlobalKeyRepeatOn | x == glut_KEY_REPEAT_DEFAULT = GlobalKeyRepeatDefault | otherwise = error ("unmarshalGlobalKeyRepeat: illegal value " ++ show x) -------------------------------------------------------------------------------- -- | Controls the key repeat mode for the window system on a global basis if -- possible. If supported by the window system, the key repeat can either be -- disabled, enabled, or set to the window system\'s default key repeat state. -- -- /X Implementation Notes:/ X11 sends @KeyPress@ events repeatedly when the -- window system\'s global auto repeat is enabled. 'perWindowKeyRepeat' can -- prevent these auto repeated keystrokes from being reported as keyboard or -- special callbacks, but there is still some minimal overhead by the X server -- to continually stream @KeyPress@ events to the GLUT application. The -- 'globalKeyRepeat' state variable can be used to actually disable the global -- sending of auto repeated @KeyPress@ events. Note that 'globalKeyRepeat' -- affects the global window system auto repeat state so other applications -- will not auto repeat if you disable auto repeat globally through -- 'globalKeyRepeat'. GLUT applications using the X11 GLUT implementation -- should disable key repeat with 'globalKeyRepeat' to disable key repeats most -- efficiently, but are responsible for explicitly restoring the default key -- repeat state on exit. -- -- /Win32 Implementation Notes:/ The Win32 implementation of 'globalKeyRepeat' -- does nothing. The 'perWindowKeyRepeat' can be used in the Win32 GLUT -- implementation to ignore repeated keys on a per-window basis without changing -- the global window system key repeat. globalKeyRepeat :: StateVar GlobalKeyRepeat globalKeyRepeat = makeStateVar (deviceGet unmarshalGlobalKeyRepeat glut_DEVICE_KEY_REPEAT) (glutSetKeyRepeat . marshalGlobalKeyRepeat) -------------------------------------------------------------------------------- -- | The state of the per-window key repeat data PerWindowKeyRepeat = PerWindowKeyRepeatOff | PerWindowKeyRepeatOn deriving ( Eq, Ord, Show ) marshalPerWindowKeyRepeat :: PerWindowKeyRepeat -> CInt marshalPerWindowKeyRepeat x = case x of PerWindowKeyRepeatOn -> 0 PerWindowKeyRepeatOff -> 1 unmarshalPerWindowKeyRepeat :: CInt -> PerWindowKeyRepeat unmarshalPerWindowKeyRepeat x | x == 0 = PerWindowKeyRepeatOn | otherwise = PerWindowKeyRepeatOff -------------------------------------------------------------------------------- -- | Controls if auto repeat keystrokes are reported to the /current window./ -- Ignoring auto repeated keystrokes is generally done in conjunction with using -- the 'Graphics.UI.GLUT.Callbacks.Window.keyboardMouseCallback'. If you do -- not ignore auto repeated keystrokes, your GLUT application will experience -- repeated release\/press callbacks. Games using the keyboard will typically -- want to ignore key repeat. perWindowKeyRepeat :: StateVar PerWindowKeyRepeat perWindowKeyRepeat = makeStateVar (deviceGet unmarshalPerWindowKeyRepeat glut_DEVICE_IGNORE_KEY_REPEAT) (glutIgnoreKeyRepeat . marshalPerWindowKeyRepeat) -------------------------------------------------------------------------------- -- | Execute the joystick callback set by -- 'Graphics.UI.GLUT.Callbacks.Window.joystickCallback' once (if one exists). -- This is done in a synchronous fashion within the current context, i.e. when -- 'forceJoystickCallback' returns, the callback will have already happened. forceJoystickCallback :: MonadIO m => m () forceJoystickCallback = glutForceJoystickFunc GLUT-2.7.0.16/src/Graphics/UI/GLUT/Fonts.hs0000644000000000000000000001145613350447541015767 0ustar0000000000000000-------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Fonts -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- GLUT supports two types of font rendering: stroke fonts, meaning each -- character is rendered as a set of line segments; and bitmap fonts, where each -- character is a bitmap generated with -- 'Graphics.Rendering.OpenGL.GL.Bitmaps.bitmap'. Stroke fonts have the -- advantage that because they are geometry, they can be arbitrarily scale and -- rendered. Bitmap fonts are less flexible since they are rendered as bitmaps -- but are usually faster than stroke fonts. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Fonts ( Font(..), BitmapFont(..), StrokeFont(..), ) where import Control.Monad.IO.Class ( MonadIO(..) ) import Data.Char ( ord ) import Foreign.C.String ( withCString ) import Foreign.C.Types ( CInt ) import Foreign.Ptr ( castPtr ) import Graphics.Rendering.OpenGL ( GLint, GLfloat ) import Graphics.UI.GLUT.Raw -------------------------------------------------------------------------------- class Font a where -- | Render the string in the named font, without using any display lists. -- Rendering a nonexistent character has no effect. -- -- If the font is a bitmap font, 'renderString' automatically sets the OpenGL -- unpack pixel storage modes it needs appropriately and saves and restores -- the previous modes before returning. The generated call to -- 'Graphics.Rendering.OpenGL.GL.bitmap' will adjust the current raster -- position based on the width of the string. -- If the font is a stroke font, -- 'Graphics.Rendering.OpenGL.GL.CoordTrans.translate' is used to translate -- the current model view matrix to advance the width of the string. renderString :: MonadIO m => a -> String -> m () -- | For a bitmap font, return the width in pixels of a string. For a stroke -- font, return the width in units. While the width of characters in a font -- may vary (though fixed width fonts do not vary), the maximum height -- characteristics of a particular font are fixed. stringWidth :: MonadIO m => a -> String -> m GLint -- | (/freeglut only/) For a bitmap font, return the maximum height of the -- characters in the given font measured in pixels. For a stroke font, -- return the height in units. fontHeight :: MonadIO m => a -> m GLfloat instance Font BitmapFont where renderString = bitmapString stringWidth = bitmapLength fontHeight = bitmapHeight instance Font StrokeFont where renderString = strokeString stringWidth = strokeLength fontHeight = strokeHeight -------------------------------------------------------------------------------- bitmapString :: MonadIO m => BitmapFont -> String -> m () bitmapString f s = do i <- marshalBitmapFont f mapM_ (\c -> withChar c (glutBitmapCharacter i)) s withChar :: Char -> (CInt -> m a) -> m a withChar c f = f . fromIntegral . ord $ c -------------------------------------------------------------------------------- strokeString :: MonadIO m => StrokeFont -> String -> m () strokeString f s = do i <- marshalStrokeFont f mapM_ (\c -> withChar c (glutStrokeCharacter i)) s -------------------------------------------------------------------------------- bitmapLength :: MonadIO m => BitmapFont -- ^ Bitmap font to use. -> String -- ^ String to return width of (not confined to 8 -- bits). -> m GLint -- ^ Width in pixels. bitmapLength f s = liftIO $ do i <- marshalBitmapFont f fmap fromIntegral $ withCString s (glutBitmapLength i . castPtr) -------------------------------------------------------------------------------- strokeLength :: MonadIO m => StrokeFont -- ^ Stroke font to use. -> String -- ^ String to return width of (not confined to 8 -- bits). -> m GLint -- ^ Width in units. strokeLength f s = liftIO $ do i <- marshalStrokeFont f fmap fromIntegral $ withCString s (glutStrokeLength i . castPtr) -------------------------------------------------------------------------------- bitmapHeight :: MonadIO m => BitmapFont -- ^ Bitmap font to use. -> m GLfloat -- ^ Height in pixels. bitmapHeight f = liftIO $ do i <- marshalBitmapFont f fromIntegral `fmap` glutBitmapHeight i -------------------------------------------------------------------------------- strokeHeight :: MonadIO m => StrokeFont -- ^ Stroke font to use. -> m GLfloat -- ^ Height in units. strokeHeight f = glutStrokeHeight =<< marshalStrokeFont f GLUT-2.7.0.16/src/Graphics/UI/GLUT/GameMode.hs0000644000000000000000000001774613255126367016370 0ustar0000000000000000-------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.GameMode -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- In addition to the functionality offered by -- 'Graphics.UI.GLUT.Window.fullScreen', GLUT offers an sub-API to change the -- screen resolution, color depth, and refresh rate of the display for a single -- full screen window. This mode of operation is called /game mode/, and is -- restricted in various ways: No pop-up menus are allowed for this full screen -- window, no other (sub-)windows can be created, and all other applications are -- hidden. -- -- /X Implementation Notes:/ Note that game mode is not fully supported in the -- original GLUT for X, it is essentially the same as using -- 'Graphics.UI.GLUT.Window.fullScreen'. The GLUT clone freeglut -- (see ) does not have this restriction. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.GameMode ( GameModeCapability(..), GameModeCapabilityDescription(..), gameModeCapabilities, enterGameMode, leaveGameMode, BitsPerPlane, RefreshRate, GameModeInfo(..), gameModeInfo, gameModeActive ) where import Control.Monad.IO.Class ( MonadIO(..) ) import Data.List ( intersperse ) import Data.StateVar ( GettableStateVar, makeGettableStateVar , SettableStateVar, makeSettableStateVar ) import Foreign.C.String ( withCString ) import Graphics.Rendering.OpenGL ( Size(..), GLenum ) import Graphics.UI.GLUT.Raw import Graphics.UI.GLUT.Types -------------------------------------------------------------------------------- -- | Capabilities for 'gameModeCapabilities' data GameModeCapability = GameModeWidth -- ^ Width of the screen resolution in pixels | GameModeHeight -- ^ Height of the screen resolution in pixels | GameModeBitsPerPlane -- ^ Color depth of the screen in bits | GameModeRefreshRate -- ^ Refresh rate in Hertz | GameModeNum -- ^ Match the Nth frame buffer configuration -- compatible with the given capabilities -- (numbering starts at 1) deriving ( Eq, Ord, Show ) gameModeCapabilityToString :: GameModeCapability -> String gameModeCapabilityToString x = case x of GameModeWidth -> "width" GameModeHeight -> "height" GameModeBitsPerPlane -> "bpp" GameModeRefreshRate -> "hertz" GameModeNum -> "num" -- | A single capability description for 'gameModeCapabilities'. data GameModeCapabilityDescription = Where' GameModeCapability Relation Int deriving ( Eq, Ord, Show ) gameModeCapabilityDescriptionToString :: GameModeCapabilityDescription -> String gameModeCapabilityDescriptionToString (Where' c r i) = gameModeCapabilityToString c ++ relationToString r ++ show i -------------------------------------------------------------------------------- -- | Controls the /game mode/ to be used when 'enterGameMode' is called. It is -- described by a list of zero or more capability descriptions, which are -- translated into a set of criteria used to select the appropriate screen -- configuration. The criteria are matched in strict left to right order of -- precdence. That is, the first specified criterion (leftmost) takes precedence -- over the later criteria for non-exact criteria -- ('Graphics.UI.GLUT.Initialization.IsGreaterThan', -- 'Graphics.UI.GLUT.Initialization.IsLessThan', etc.). Exact criteria -- ('Graphics.UI.GLUT.Initialization.IsEqualTo', -- 'Graphics.UI.GLUT.Initialization.IsNotEqualTo') must match exactly so -- precedence is not relevant. -- -- To determine which configuration will actually be tried by 'enterGameMode' -- (if any), use 'gameModeInfo'. -- -- Note that even for game mode the current values of -- 'Graphics.UI.GLUT.Initialization.initialDisplayMode'or -- 'Graphics.UI.GLUT.Initialization.initialDisplayCapabilities' will -- determine which buffers are available, if double buffering is used or not, -- etc. gameModeCapabilities :: SettableStateVar [GameModeCapabilityDescription] gameModeCapabilities = makeSettableStateVar $ \ds -> withCString (descriptionsToString ds) glutGameModeString -- freeglut currently handles only simple game mode descriptions like "WxH:B@R", -- so we try hard to use this format instead of the more general format allowed -- by the "real" GLUT. descriptionsToString :: [GameModeCapabilityDescription] -> String descriptionsToString ds = let ws = [ x | Where' GameModeWidth IsEqualTo x <- ds ] hs = [ x | Where' GameModeHeight IsEqualTo x <- ds ] bs = [ x | Where' GameModeBitsPerPlane IsEqualTo x <- ds ] rs = [ x | Where' GameModeRefreshRate IsEqualTo x <- ds ] allSimple = (length ws + length hs + length bs + length rs) == (length ds) dimensionsOK = (null ws) == (null hs) in if allSimple && dimensionsOK then simpleCapStr ws hs bs rs else generalCapStr ds simpleCapStr :: [Int] -> [Int] -> [Int] -> [Int] -> String simpleCapStr ws hs bs rs = showCap "" ws ++ showCap "x" hs ++ showCap ":" bs ++ showCap "@" rs where showCap _ [] = "" showCap prefix (x:_) = prefix ++ show x generalCapStr :: [GameModeCapabilityDescription] -> String generalCapStr = concat . intersperse " " . map gameModeCapabilityDescriptionToString -------------------------------------------------------------------------------- -- | Enter /game mode/, trying to change resolution, refresh rate, etc., as -- specified by the current value of 'gameModeCapabilities'. An identifier for -- the game mode window and a flag, indicating if the display mode actually -- changed, are returned. The game mode window is made the /current window/. -- -- Re-entering /game mode/ is allowed, the previous game mode window gets -- destroyed by this, and a new one is created. enterGameMode :: MonadIO m => m (Window, Bool) enterGameMode = do w <- glutEnterGameMode c <- getBool glut_GAME_MODE_DISPLAY_CHANGED return (Window w, c) -------------------------------------------------------------------------------- -- | Leave /game mode/, restoring the old display mode and destroying the game -- mode window. leaveGameMode :: MonadIO m => m () leaveGameMode = glutLeaveGameMode -------------------------------------------------------------------------------- -- | The color depth of the screen, measured in bits (e.g. 8, 16, 24, 32, ...) type BitsPerPlane = Int -- | The refresh rate of the screen, measured in Hertz (e.g. 60, 75, 100, ...) type RefreshRate = Int data GameModeInfo = GameModeInfo Size BitsPerPlane RefreshRate deriving ( Eq, Ord, Show ) -------------------------------------------------------------------------------- -- | Return 'Just' the mode which would be tried by the next call to -- 'enterGameMode'. Returns 'Nothing' if the mode requested by the current value -- of 'gameModeCapabilities' is not possible, in which case 'enterGameMode' -- would simply create a full screen window using the current mode. gameModeInfo :: GettableStateVar (Maybe GameModeInfo) gameModeInfo = makeGettableStateVar $ do possible <- getBool glut_GAME_MODE_POSSIBLE if possible then do w <- glutGameModeGet glut_GAME_MODE_WIDTH h <- glutGameModeGet glut_GAME_MODE_HEIGHT let size = Size (fromIntegral w) (fromIntegral h) b <- glutGameModeGet glut_GAME_MODE_PIXEL_DEPTH r <- glutGameModeGet glut_GAME_MODE_REFRESH_RATE return $ Just $ GameModeInfo size (fromIntegral b) (fromIntegral r) else return Nothing getBool :: MonadIO m => GLenum -> m Bool getBool x = do val <- glutGameModeGet x return $ val /= 0 -------------------------------------------------------------------------------- -- | Contains 'True' when the /game mode/ is active, 'False' otherwise. gameModeActive :: GettableStateVar Bool gameModeActive = makeGettableStateVar $ getBool glut_GAME_MODE_ACTIVE GLUT-2.7.0.16/src/Graphics/UI/GLUT/Initialization.hs0000644000000000000000000010624113255126367017666 0ustar0000000000000000-------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Initialization -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- Actions and state variables in this module are used to initialize GLUT state. -- The primary initialization routine is 'initialize', which should only be -- called exactly once in a GLUT program. No other GLUT or OpenGL actions should -- be called before 'initialize', apart from getting or setting the state -- variables in this module. -- -- The reason is that these state variables can be used to set default window -- initialization state that might be modified by the command processing done in -- 'initialize'. For example, 'initialWindowSize' can be set to @('Size' -- 400 400)@ before 'initialize' is called to indicate 400 by 400 is the -- program\'s default window size. Setting the initial window size or position -- before 'initialize' allows the GLUT program user to specify the initial size -- or position using command line arguments. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Initialization ( -- * Primary initialization initialize, getArgsAndInitialize, exit, -- * Initial window geometry initialWindowPosition, initialWindowSize, -- * Setting the initial display mode (I) DisplayMode(..), initialDisplayMode, displayModePossible, -- * Setting the initial display mode (II) DisplayCapability(..), Relation(..), DisplayCapabilityDescription(..), initialDisplayCapabilities, -- * Controlling the creation of rendering contexts RenderingContext(..), renderingContext, -- * Direct\/indirect rendering DirectRendering(..), directRendering, -- * OpenGL 3.x context support initialContextVersion, ContextFlag(..), initialContextFlags, ContextProfile(..), initialContextProfile ) where import Control.Monad ( when ) import Control.Monad.IO.Class ( MonadIO(..) ) import Data.Bits ( Bits(..) ) import Data.List ( genericLength, intersperse, mapAccumR ) import Data.StateVar ( get, ($=), GettableStateVar, makeGettableStateVar , SettableStateVar, makeSettableStateVar, StateVar, makeStateVar ) import Foreign.C.String ( peekCString, withCString ) import Foreign.C.Types ( CInt, CUInt ) import Foreign.Marshal.Array ( peekArray, withArray0 ) import Foreign.Marshal.Utils ( with, withMany ) import Foreign.Ptr ( nullPtr ) import Foreign.Storable ( peek ) import Graphics.Rendering.OpenGL ( Position(..), Size(..) ) import System.Environment ( getArgs, getProgName ) import Graphics.UI.GLUT.QueryUtils import Graphics.UI.GLUT.Raw import Graphics.UI.GLUT.Types -------------------------------------------------------------------------------- -- | Given the program name and command line arguments, initialize the GLUT -- library and negotiate a session with the window system. During this -- process, 'initialize' may cause the termination of the GLUT program with an -- error message to the user if GLUT cannot be properly initialized. -- Examples of this situation include the failure to connect to the window -- system, the lack of window system support for OpenGL, and invalid command -- line options. -- -- 'initialize' also processes command line options, but the specific options -- parsed are window system dependent. Any command line arguments which are -- not GLUT-specific are returned. -- -- /X Implementation Notes:/ The X Window System specific options parsed by -- 'initialize' are as follows: -- -- * @-display /DISPLAY/@: Specify the X server to connect to. If not specified, -- the value of the @DISPLAY@ environment variable is used. -- -- * @-geometry /WxH+X+Y/@: Determines where windows should be created on the -- screen. The parameter following @-geometry@ should be formatted as a -- standard X geometry specification. The effect of using this option is to -- change the GLUT initial size and initial position the same as if -- 'initialWindowSize' or 'initialWindowPosition' were modified directly. -- -- * @-iconic@: Requests all top-level windows be created in an iconic state. -- -- * @-indirect@: Force the use of indirect OpenGL rendering contexts. -- -- * @-direct@: Force the use of direct OpenGL rendering contexts (not all GLX -- implementations support direct rendering contexts). A fatal error is -- generated if direct rendering is not supported by the OpenGL -- implementation. If neither @-indirect@ or @-direct@ are used to force a -- particular behavior, GLUT will attempt to use direct rendering if -- possible and otherwise fallback to indirect rendering. -- -- * @-gldebug@: After processing callbacks and\/or events, call -- 'Graphics.UI.GLUT.Debugging.reportErrors' to check if there are any pending -- OpenGL errors. Using this option is helpful in detecting OpenGL run-time -- errors. -- -- * @-sync@: Enable synchronous X protocol transactions. This option makes -- it easier to track down potential X protocol errors. initialize :: MonadIO m => String -- ^ The program name. -> [String] -- ^ The command line arguments -> m [String] -- ^ Non-GLUT command line arguments initialize prog args = liftIO $ with (1 + genericLength args) $ \argcBuf -> withMany withCString (prog : args) $ \argvPtrs -> withArray0 nullPtr argvPtrs $ \argvBuf -> do glutInit argcBuf argvBuf newArgc <- peek argcBuf newArgvPtrs <- peekArray (fromIntegral newArgc) argvBuf newArgv <- mapM peekCString newArgvPtrs return $ tail newArgv -- | Convenience action: Initialize GLUT, returning the program name and any -- non-GLUT command line arguments. getArgsAndInitialize :: MonadIO m => m (String, [String]) getArgsAndInitialize = liftIO $ do prog <- getProgName args <- getArgs nonGLUTArgs <- initialize prog args return (prog, nonGLUTArgs) ----------------------------------------------------------------------------- -- | (/freeglut only/) De-initialize GLUT. After this, one has to use -- 'initialize' or 'getArgsAndInitialize' to initialize GLUT again. exit :: MonadIO m => m () exit = glutExit -------------------------------------------------------------------------------- -- | Controls the /initial window position/. Windows created by -- 'Graphics.UI.GLUT.Window.createWindow' will be requested to be created with -- the current /initial window position/. The initial value of the /initial -- window position/ GLUT state is @'Position' (-1) (-1)@. If either the X or Y -- component of the /initial window position/ is negative, the actual window -- position is left to the window system to determine. -- -- The intent of the /initial window position/ is to provide a suggestion to -- the window system for a window\'s initial position. The window system is -- not obligated to use this information. Therefore, GLUT programs should not -- assume the window was created at the specified position. initialWindowPosition :: StateVar Position initialWindowPosition = makeStateVar getInitialWindowPosition setInitialWindowPosition getInitialWindowPosition :: IO Position getInitialWindowPosition = do x <- simpleGet fromIntegral glut_INIT_WINDOW_X y <- simpleGet fromIntegral glut_INIT_WINDOW_Y return $ Position x y setInitialWindowPosition :: Position -> IO () setInitialWindowPosition (Position x y) = glutInitWindowPosition (fromIntegral x) (fromIntegral y) -------------------------------------------------------------------------------- -- | Controls the /initial window size/. Windows created by -- 'Graphics.UI.GLUT.Window.createWindow' will be requested to be created with -- the current /initial window size/. The initial value of the /initial window -- size/ GLUT state is @'Size' 300 300@. If either the width or the height -- component of the /initial window size/ is non-positive, the actual window -- size is left to the window system to determine. -- -- The intent of the /initial window size/ is to provide a suggestion to the -- window system for a window\'s initial size. The window system is not -- obligated to use this information. Therefore, GLUT programs should not -- assume the window was created at the specified size. A GLUT program should -- use the window\'s reshape callback to determine the true size of the -- window. initialWindowSize :: StateVar Size initialWindowSize = makeStateVar getInitialWindowSize setInitialWindowSize getInitialWindowSize :: IO Size getInitialWindowSize = do w <- simpleGet fromIntegral glut_INIT_WINDOW_WIDTH h <- simpleGet fromIntegral glut_INIT_WINDOW_HEIGHT return $ Size w h setInitialWindowSize :: Size -> IO () setInitialWindowSize (Size w h) = glutInitWindowSize (fromIntegral w) (fromIntegral h) -------------------------------------------------------------------------------- -- | A single aspect of a window which is to be created, used in conjunction -- with 'initialDisplayMode'. data DisplayMode = RGBAMode -- ^ Select an RGBA mode window. This is the default if neither 'RGBAMode' -- nor 'IndexMode' are specified. | RGBMode -- ^ An alias for 'RGBAMode'. | IndexMode -- ^ Select a color index mode window. This overrides 'RGBAMode' if it is -- also specified. | LuminanceMode -- ^ Select a window with a \"luminance\" color model. This model provides -- the functionality of OpenGL\'s RGBA color model, but the green and blue -- components are not maintained in the frame buffer. Instead each pixel\'s -- red component is converted to an index between zero and -- 'Graphics.UI.GLUT.Colormap.numColorMapEntries' and looked up in a -- per-window color map to determine the color of pixels within the window. -- The initial colormap of 'LuminanceMode' windows is initialized to be a -- linear gray ramp, but can be modified with GLUT\'s colormap actions. -- /Implementation Notes:/ 'LuminanceMode' is not supported on most OpenGL -- platforms. | WithAlphaComponent -- ^ Select a window with an alpha component to the color buffer(s). | WithAccumBuffer -- ^ Select a window with an accumulation buffer. | WithDepthBuffer -- ^ Select a window with a depth buffer. | WithStencilBuffer -- ^ Select a window with a stencil buffer. | WithAuxBuffers Int -- ^ (/freeglut only/) Select a window with /n/ (1 .. 4) auxiliary buffers. -- Any /n/ outside the range 1 .. 4 is a fatal error. | SingleBuffered -- ^ Select a single buffered window. This is the default if neither -- 'DoubleBuffered' nor 'SingleBuffered' are specified. | DoubleBuffered -- ^ Select a double buffered window. This overrides 'SingleBuffered' if it -- is also specified. | Multisampling -- ^ Select a window with multisampling support. If multisampling is not -- available, a non-multisampling window will automatically be chosen. -- Note: both the OpenGL client-side and server-side implementations must -- support the @GLX_SAMPLE_SGIS@ extension for multisampling to be -- available. Deprecated, use 'WithSamplesPerPixel'. | WithSamplesPerPixel Int -- ^ Select a window with multisampling, using the given samples per pixel. | Stereoscopic -- ^ Select a stereo window. | Captionless -- ^ Select a window without a caption (/freeglut only/). | Borderless -- ^ Select a window without any borders (/freeglut only/). | SRGBMode -- ^ Select an sRGB mode window (/freeglut only/). deriving ( Eq, Ord, Show ) marshalDisplayMode :: DisplayMode -> CUInt marshalDisplayMode m = case m of RGBAMode -> glut_RGBA RGBMode -> glut_RGB IndexMode -> glut_INDEX LuminanceMode -> glut_LUMINANCE WithAlphaComponent -> glut_ALPHA WithAccumBuffer -> glut_ACCUM WithDepthBuffer -> glut_DEPTH WithStencilBuffer -> glut_STENCIL WithAuxBuffers 1 -> glut_AUX1 WithAuxBuffers 2 -> glut_AUX2 WithAuxBuffers 3 -> glut_AUX3 WithAuxBuffers 4 -> glut_AUX4 WithAuxBuffers n -> error ("marshalDisplayMode: illegal number of auxiliary buffers: " ++ show n) SingleBuffered -> glut_SINGLE DoubleBuffered -> glut_DOUBLE Multisampling -> glut_MULTISAMPLE WithSamplesPerPixel _ -> error ("marshalDisplayMode: this should not happen") Stereoscopic -> glut_STEREO Captionless -> glut_CAPTIONLESS Borderless -> glut_BORDERLESS SRGBMode -> glut_SRGB -------------------------------------------------------------------------------- -- | Controls the /initial display mode/ used when creating top-level windows, -- subwindows, and overlays to determine the OpenGL display mode for the -- to-be-created window or overlay. -- -- Note that 'RGBAMode' selects the RGBA color model, but it does not request any -- bits of alpha (sometimes called an /alpha buffer/ or /destination alpha/) -- be allocated. To request alpha, specify 'WithAlphaComponent'. The same -- applies to 'LuminanceMode'. initialDisplayMode :: StateVar [DisplayMode] initialDisplayMode = makeStateVar getInitialDisplayMode setInitialDisplayMode getInitialDisplayMode :: IO [DisplayMode] getInitialDisplayMode = do mode <- simpleGet fromIntegral glut_INIT_DISPLAY_MODE let displayModes = i2dms (mode .&. complement glut_MULTISAMPLE) if mode .&. glut_MULTISAMPLE == 0 then return displayModes else do n <- get samplesPerPixel return $ WithSamplesPerPixel n : displayModes i2dms :: CUInt -> [DisplayMode] i2dms bitfield | IndexMode `elem` modes || LuminanceMode `elem` modes = modes | otherwise = RGBAMode : modes where modes = i2dmsWithoutRGBA bitfield i2dmsWithoutRGBA :: CUInt -> [DisplayMode] i2dmsWithoutRGBA bitfield = [ c | c <- [ IndexMode, LuminanceMode, WithAlphaComponent, WithAccumBuffer, WithDepthBuffer, WithStencilBuffer, WithAuxBuffers 1, WithAuxBuffers 2, WithAuxBuffers 3, WithAuxBuffers 4, SingleBuffered, DoubleBuffered, Multisampling, Stereoscopic, Captionless, Borderless, SRGBMode ] , (bitfield .&. marshalDisplayMode c) /= 0 ] setInitialDisplayMode :: [DisplayMode] -> IO () setInitialDisplayMode modes = do let (spps, transformedModes) = mapAccumR handleMultisampling [] modes mapM_ (samplesPerPixel $=) spps glutInitDisplayMode (toBitfield marshalDisplayMode transformedModes) handleMultisampling :: [Int] -> DisplayMode -> ([Int], DisplayMode) handleMultisampling spps (WithSamplesPerPixel spp) = (spp : spps, Multisampling) handleMultisampling spps mode = (spps, mode) toBitfield :: (Num b, Bits b) => (a -> b) -> [a] -> b toBitfield marshal = foldl (.|.) 0 . map marshal -- | Contains 'True' if the /current display mode/ is supported, 'False' -- otherwise. displayModePossible :: GettableStateVar Bool displayModePossible = makeGettableStateVar $ simpleGet (/= 0) glut_DISPLAY_MODE_POSSIBLE -------------------------------------------------------------------------------- samplesPerPixel :: StateVar Int samplesPerPixel = makeStateVar getSamplesPerPixel setSamplesPerPixel getSamplesPerPixel :: IO Int getSamplesPerPixel = do m <- multisamplingSupported if m then simpleGet fromIntegral (fromIntegral glut_MULTISAMPLE) else return defaultSamplesPerPixels defaultSamplesPerPixels :: Int defaultSamplesPerPixels = 4 setSamplesPerPixel :: Int -> IO () setSamplesPerPixel spp = do m <- multisamplingSupported when m $ glutSetOption (fromIntegral glut_MULTISAMPLE) (fromIntegral spp) multisamplingSupported :: IO Bool multisamplingSupported = isKnown "glutGetModeValues" -------------------------------------------------------------------------------- -- | Capabilities for 'initialDisplayCapabilities', most of them are extensions -- of the constructors of 'DisplayMode'. data DisplayCapability = DisplayRGBA -- ^ Number of bits of red, green, blue, and alpha in the RGBA -- color buffer. Default is \"'IsAtLeast' @1@\" for red, -- green, blue, and alpha capabilities, and \"'IsEqualTo' -- @1@\" for the RGBA color model capability. | DisplayRGB -- ^ Number of bits of red, green, and blue in the RGBA color -- buffer and zero bits of alpha color buffer precision. -- Default is \"'IsAtLeast' @1@\" for the red, green, and -- blue capabilities, and \"'IsNotLessThan' @0@\" for alpha -- capability, and \"'IsEqualTo' @1@\" for the RGBA color -- model capability. | DisplayRed -- ^ Red color buffer precision in bits. Default is -- \"'IsAtLeast' @1@\". | DisplayGreen -- ^ Green color buffer precision in bits. Default is -- \"'IsAtLeast' @1@\". | DisplayBlue -- ^ Blue color buffer precision in bits. Default is -- \"'IsAtLeast' @1@\". | DisplayIndex -- ^ Boolean if the color model is color index or not. True is -- color index. Default is \"'IsAtLeast' @1@\". | DisplayBuffer -- ^ Number of bits in the color index color buffer. Default -- is \"'IsAtLeast' @1@\". | DisplaySingle -- ^ Boolean indicate the color buffer is single buffered. -- Default is \"'IsEqualTo' @1@\". | DisplayDouble -- ^ Boolean indicating if the color buffer is double -- buffered. Default is \"'IsEqualTo' @1@\". | DisplayAccA -- ^ Red, green, blue, and alpha accumulation buffer precision -- in bits. Default is \"'IsAtLeast' @1@\" for red, green, -- blue, and alpha capabilities. | DisplayAcc -- ^ Red, green, and green accumulation buffer precision in -- bits and zero bits of alpha accumulation buffer precision. -- Default is \"'IsAtLeast' @1@\" for red, green, and blue -- capabilities, and \"'IsNotLessThan' @0@\" for the alpha -- capability. | DisplayAlpha -- ^ Alpha color buffer precision in bits. Default is -- \"'IsAtLeast' @1@\". | DisplayDepth -- ^ Number of bits of precsion in the depth buffer. Default -- is \"'IsAtLeast' @12@\". | DisplayStencil -- ^ Number of bits in the stencil buffer. Default is -- \"'IsNotLessThan' @1@\". | DisplaySamples -- ^ Indicates the number of multisamples to use based on -- GLX\'s @SGIS_multisample@ extension (for antialiasing). -- Default is \"'IsNotGreaterThan' @4@\". This default means -- that a GLUT application can request multisampling if -- available by simply specifying \"'With' 'DisplaySamples'\". | DisplayStereo -- ^ Boolean indicating the color buffer is supports -- OpenGL-style stereo. Default is \"'IsEqualTo' @1@\". | DisplayLuminance -- ^ Number of bits of red in the RGBA and zero bits of green, -- blue (alpha not specified) of color buffer precision. -- Default is \"'IsAtLeast' @1@\" for the red capabilitis, -- and \"'IsEqualTo' @0@\" for the green and blue -- capabilities, and \"'IsEqualTo' @1@\" for the RGBA color -- model capability, and, for X11, \"'IsEqualTo' @1@\" for -- the 'DisplayXStaticGray' capability. SGI InfiniteReality (and -- other future machines) support a 16-bit luminance (single -- channel) display mode (an additional 16-bit alpha channel -- can also be requested). The red channel maps to gray -- scale and green and blue channels are not available. A -- 16-bit precision luminance display mode is often -- appropriate for medical imaging applications. Do not -- expect many machines to support extended precision -- luminance display modes. | DisplayAux -- ^ (/freeglut only/) Number of auxiliary buffers. Default is -- \"'IsEqualTo' @1@\". | DisplayNum -- ^ A special capability name indicating where the value -- represents the Nth frame buffer configuration matching -- the description string. When not specified, -- 'initialDisplayCapabilities' also uses the first -- (best matching) configuration. 'Num' requires a relation -- and numeric value. | DisplayConformant -- ^ Boolean indicating if the frame buffer configuration is -- conformant or not. Conformance information is based on -- GLX\'s @EXT_visual_rating@ extension if supported. If the -- extension is not supported, all visuals are assumed -- conformant. Default is \"'IsEqualTo' @1@\". | DisplaySlow -- ^ Boolean indicating if the frame buffer configuration is -- slow or not. Slowness information is based on GLX\'s -- @EXT_visual_rating@ extension if supported. If the -- extension is not supported, all visuals are assumed fast. -- Note that slowness is a relative designation relative to -- other frame buffer configurations available. The intent -- of the slow capability is to help programs avoid frame -- buffer configurations that are slower (but perhaps higher -- precision) for the current machine. Default is -- \"'IsAtLeast' @0@\". This default means that slow visuals -- are used in preference to fast visuals, but fast visuals -- will still be allowed. | DisplayWin32PFD -- ^ Only recognized on GLUT implementations for Win32, this -- capability name matches the Win32 Pixel Format Descriptor -- by number. 'DisplayWin32PFD' can only be used with 'Where'. | DisplayXVisual -- ^ Only recongized on GLUT implementations for the X Window -- System, this capability name matches the X visual ID by -- number. 'DisplayXVisual' requires a relation and numeric value. | DisplayXStaticGray -- ^ Only recongized on GLUT implementations for the X Window -- System, boolean indicating if the frame buffer -- configuration\'s X visual is of type @StaticGray@. -- Default is \"'IsEqualTo' @1@\". | DisplayXGrayScale -- ^ Only recongized on GLUT implementations for the X Window -- System, boolean indicating if the frame buffer -- configuration\'s X visual is of type @GrayScale@. Default -- is \"'IsEqualTo' @1@\". | DisplayXStaticColor -- ^ Only recongized on GLUT implementations for the X Window -- System, boolean indicating if the frame buffer -- configuration\'s X visual is of type @StaticColor@. -- Default is \"'IsEqualTo' @1@\". | DisplayXPseudoColor -- ^ Only recongized on GLUT implementations for the X Window -- System, boolean indicating if the frame buffer -- configuration\'s X visual is of type @PsuedoColor@. -- Default is \"'IsEqualTo' @1@\". | DisplayXTrueColor -- ^ Only recongized on GLUT implementations for the X Window -- System, boolean indicating if the frame buffer -- configuration\'s X visual is of type @TrueColor@. Default -- is \"'IsEqualTo' @1@\". | DisplayXDirectColor -- ^ Only recongized on GLUT implementations for the X Window -- System, boolean indicating if the frame buffer -- configuration\'s X visual is of type @DirectColor@. -- Default is \"'IsEqualTo' @1@\". deriving ( Eq, Ord, Show ) displayCapabilityToString :: DisplayCapability -> String displayCapabilityToString x = case x of DisplayRGBA -> "rgba" DisplayRGB -> "rgb" DisplayRed -> "red" DisplayGreen -> "green" DisplayBlue -> "blue" DisplayIndex -> "index" DisplayBuffer -> "buffer" DisplaySingle -> "single" DisplayDouble -> "double" DisplayAccA -> "acca" DisplayAcc -> "acc" DisplayAlpha -> "alpha" DisplayDepth -> "depth" DisplayStencil -> "stencil" DisplaySamples -> "samples" DisplayStereo -> "stereo" DisplayLuminance -> "luminance" DisplayAux -> "aux" DisplayNum -> "num" DisplayConformant -> "conformant" DisplaySlow -> "slow" DisplayWin32PFD -> "win32pfd" DisplayXVisual -> "xvisual" DisplayXStaticGray -> "xstaticgray" DisplayXGrayScale -> "xgrayscale" DisplayXStaticColor -> "xstaticcolor" DisplayXPseudoColor -> "xpseudocolor" DisplayXTrueColor -> "xtruecolor" DisplayXDirectColor -> "xdirectcolor" -- | A single capability description for 'initialDisplayCapabilities'. data DisplayCapabilityDescription = Where DisplayCapability Relation Int -- ^ A description of a capability with a specific relation to a numeric -- value. | With DisplayCapability -- ^ When the relation and numeric value are not specified, each capability -- has a different default, see the different constructors of -- 'DisplayCapability'. deriving ( Eq, Ord, Show ) displayCapabilityDescriptionToString :: DisplayCapabilityDescription -> String displayCapabilityDescriptionToString (Where c r i) = displayCapabilityToString c ++ relationToString r ++ show i displayCapabilityDescriptionToString (With c) = displayCapabilityToString c -- | Controls the /initial display mode/ used when creating top-level windows, -- subwindows, and overlays to determine the OpenGL display mode for the -- to-be-created window or overlay. It is described by a list of zero or more -- capability descriptions, which are translated into a set of criteria used to -- select the appropriate frame buffer configuration. The criteria are matched -- in strict left to right order of precdence. That is, the first specified -- criterion (leftmost) takes precedence over the later criteria for non-exact -- criteria ('IsGreaterThan', 'IsLessThan', etc.). Exact criteria ('IsEqualTo', -- 'IsNotEqualTo') must match exactly so precedence is not relevant. -- -- Unspecified capability descriptions will result in unspecified criteria being -- generated. These unspecified criteria help 'initialDisplayCapabilities' -- behave sensibly with terse display mode descriptions. -- -- Here is an example using 'initialDisplayCapabilities': -- -- @ -- initialDisplayCapabilities $= [ With DisplayRGB, -- Where DisplayDepth IsAtLeast 16, -- With DisplaySamples, -- Where DisplayStencil IsNotLessThan 2, -- With DisplayDouble ] -- @ -- -- The above call requests a window with an RGBA color model (but requesting -- no bits of alpha), a depth buffer with at least 16 bits of precision but -- preferring more, multisampling if available, at least 2 bits of stencil -- (favoring less stencil to more as long as 2 bits are available), and double -- buffering. initialDisplayCapabilities :: SettableStateVar [DisplayCapabilityDescription] initialDisplayCapabilities = makeSettableStateVar $ \caps -> withCString (concat . intersperse " " . map displayCapabilityDescriptionToString $ caps) glutInitDisplayString ----------------------------------------------------------------------------- -- | How rendering context for new windows are created. data RenderingContext = -- | Create a new context via @glXCreateContext@ or @wglCreateContext@ -- (default). CreateNewContext | -- | Re-use the current rendering context. UseCurrentContext deriving ( Eq, Ord, Show ) marshalRenderingContext :: RenderingContext -> CInt marshalRenderingContext CreateNewContext = glut_CREATE_NEW_CONTEXT marshalRenderingContext UseCurrentContext = glut_USE_CURRENT_CONTEXT unmarshalRenderingContext :: CInt -> RenderingContext unmarshalRenderingContext r | r == glut_CREATE_NEW_CONTEXT = CreateNewContext | r == glut_USE_CURRENT_CONTEXT = UseCurrentContext | otherwise = error "unmarshalRenderingContext" ----------------------------------------------------------------------------- -- | (/freeglut only/) Controls the creation of rendering contexts for new -- windows. renderingContext :: StateVar RenderingContext renderingContext = makeStateVar (simpleGet unmarshalRenderingContext glut_RENDERING_CONTEXT) (glutSetOption glut_RENDERING_CONTEXT . marshalRenderingContext) ----------------------------------------------------------------------------- -- | The kind of GLX rendering context used. Direct rendering provides a -- performance advantage in some implementations. However, direct rendering -- contexts cannot be shared outside a single process, and they may be unable -- to render to GLX pixmaps. data DirectRendering = -- | Rendering is always done through the X server. This corresponds to -- the command line argument @-indirect@, see 'initialize'. ForceIndirectContext | -- | Try to use direct rendering, silently using indirect rendering if this -- is not possible. AllowDirectContext | -- | Try to use direct rendering, issue a warning and use indirect -- rendering if this is not possible. TryDirectContext | -- | Try to use direct rendering, issue an error and terminate the program -- if this is not possible.This corresponds to the command line argument -- @-direct@, see 'initialize'. ForceDirectContext deriving ( Eq, Ord, Show ) marshalDirectRendering :: DirectRendering -> CInt marshalDirectRendering x = case x of ForceIndirectContext -> glut_FORCE_INDIRECT_CONTEXT AllowDirectContext -> glut_ALLOW_DIRECT_CONTEXT TryDirectContext -> glut_TRY_DIRECT_CONTEXT ForceDirectContext -> glut_FORCE_DIRECT_CONTEXT unmarshalDirectRendering :: CInt -> DirectRendering unmarshalDirectRendering x | x == glut_FORCE_INDIRECT_CONTEXT = ForceIndirectContext | x == glut_ALLOW_DIRECT_CONTEXT = AllowDirectContext | x == glut_TRY_DIRECT_CONTEXT = TryDirectContext | x == glut_FORCE_DIRECT_CONTEXT = ForceDirectContext | otherwise = error ("unmarshalDirectRendering: illegal value " ++ show x) ----------------------------------------------------------------------------- -- | (/freeglut on X11 only/) Controls which kind of rendering context is -- created when a new one is required. directRendering :: StateVar DirectRendering directRendering = makeStateVar (simpleGet unmarshalDirectRendering glut_DIRECT_RENDERING) (glutSetOption glut_DIRECT_RENDERING . marshalDirectRendering) ----------------------------------------------------------------------------- -- | (/freeglut only/) Controls the API major\/minor version of the OpenGL -- context. If a version less than or equal to 2.1 is requested, the context -- returned may implement any version no less than that requested and no -- greater than 2.1. If version 3.0 is requested, the context returned must -- implement exactly version 3.0. Versioning behavior once GL versions beyond -- 3.0 are defined will be defined by an amendment to the OpenGL specification -- to define dependencies on such GL versions. -- -- 'Graphics.Rendering.OpenGL.GL.StringQueries.glVersion' and -- 'Graphics.Rendering.OpenGL.GL.StringQueries.majorMinor' will return the -- actual version supported by a context. -- -- The default context version is (1, 0), which will typically return an -- OpenGL 2.1 context, if one is available. initialContextVersion :: StateVar (Int, Int) initialContextVersion = makeStateVar getContextVersion setContextVersion getContextVersion :: IO (Int, Int) getContextVersion = do major <- simpleGet fromIntegral glut_INIT_MAJOR_VERSION minor <- simpleGet fromIntegral glut_INIT_MINOR_VERSION return (major, minor) setContextVersion :: (Int, Int) -> IO () setContextVersion (major, minor) = glutInitContextVersion (fromIntegral major) (fromIntegral minor) ----------------------------------------------------------------------------- -- | A flag affecting the rendering context to create, used in conjunction -- with 'initialContextFlags'. data ContextFlag = -- | Debug contexts are intended for use during application development, -- and provide additional runtime checking, validation, and logging -- functionality while possibly incurring performance penalties. The -- additional functionality provided by debug contexts may vary according -- to the implementation. In some cases a debug context may be identical -- to a non-debug context. DebugContext | -- | Forward-compatible contexts are defined only for OpenGL versions 3.0 -- and later. They must not support functionality marked as /deprecated/ -- by that version of the API, while a non-forward-compatible context must -- support all functionality in that version, deprecated or not. ForwardCompatibleContext deriving ( Eq, Ord, Show ) marshalContextFlag :: ContextFlag -> CInt marshalContextFlag x = case x of DebugContext -> glut_DEBUG ForwardCompatibleContext -> glut_FORWARD_COMPATIBLE ----------------------------------------------------------------------------- -- | (/freeglut only/) Controls the set of flags for the rendering context. initialContextFlags :: StateVar [ContextFlag] initialContextFlags = makeStateVar getContextFlags setContextFlags getContextFlags :: IO [ContextFlag] getContextFlags = simpleGet i2cfs glut_INIT_FLAGS i2cfs :: CInt -> [ContextFlag] i2cfs bitfield = [ c | c <- [ DebugContext, ForwardCompatibleContext ] , (fromIntegral bitfield .&. marshalContextFlag c) /= 0 ] setContextFlags :: [ContextFlag] -> IO () setContextFlags = glutInitContextFlags . toBitfield marshalContextFlag ----------------------------------------------------------------------------- -- | An OpenGL API profile, affecting the rendering context to create, used -- in conjunction with 'initialContextProfile'. data ContextProfile = -- | The OpenGL /core/ profile, which all OpenGL 3.2 implementations -- are required to support. CoreProfile | -- | The OpenGL /compatibility/ profile, which is optional for OpenGL -- 3.2 implementations. CompatibilityProfile deriving ( Eq, Ord, Show ) marshalContextProfile :: ContextProfile -> CInt marshalContextProfile x = case x of CoreProfile -> glut_CORE_PROFILE CompatibilityProfile -> glut_COMPATIBILITY_PROFILE ----------------------------------------------------------------------------- -- | (/freeglut only/) Controls the set of profiles for the rendering context. initialContextProfile :: StateVar [ContextProfile] initialContextProfile = makeStateVar getContextProfiles setContextProfiles getContextProfiles :: IO [ContextProfile] getContextProfiles = simpleGet i2cps glut_INIT_PROFILE i2cps :: CInt -> [ContextProfile] i2cps bitfield = [ c | c <- [ CoreProfile, CompatibilityProfile ] , (fromIntegral bitfield .&. marshalContextProfile c) /= 0 ] setContextProfiles :: [ContextProfile] -> IO () setContextProfiles = glutInitContextProfile . toBitfield marshalContextProfile GLUT-2.7.0.16/src/Graphics/UI/GLUT/Menu.hs0000644000000000000000000002373513255126367015611 0ustar0000000000000000{-# OPTIONS_GHC -fno-cse #-} -------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Menu -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- GLUT supports simple cascading pop-up menus. They are designed to let a user -- select various modes within a program. The functionality is simple and -- minimalistic and is meant to be that way. Do not mistake GLUT\'s pop-up menu -- facility with an attempt to create a full-featured user interface. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Menu ( Menu(..), MenuItem(..), MenuCallback, attachMenu, numMenuItems ) where import Control.Monad.IO.Class ( MonadIO(..) ) import Control.Monad ( when, unless, zipWithM ) import Data.Array ( listArray, (!) ) import Data.IORef ( IORef, newIORef, readIORef, modifyIORef ) import qualified Data.Map as M import Data.StateVar ( get, ($=), GettableStateVar, makeGettableStateVar , StateVar, makeStateVar ) import Foreign.C.String ( withCString ) import Foreign.C.Types ( CInt ) import Foreign.Ptr ( freeHaskellFunPtr ) import System.IO.Unsafe ( unsafePerformIO ) import Graphics.UI.GLUT.Callbacks.Registration import Graphics.UI.GLUT.QueryUtils import Graphics.UI.GLUT.Raw import Graphics.UI.GLUT.Types -------------------------------------------------------------------------------- -- | A menu is simply a list of menu items, possibly with an associated font. data Menu = Menu [MenuItem] | MenuWithFont BitmapFont [MenuItem] menuFont :: Menu -> Maybe BitmapFont menuFont (Menu _) = Nothing menuFont (MenuWithFont font _) = Just font menuItems :: Menu -> [MenuItem] menuItems (Menu items) = items menuItems (MenuWithFont _ items) = items -- | A single item within a menu can either be a plain menu entry or a sub-menu -- entry, allowing for arbitrarily deep nested menus. data MenuItem = MenuEntry String MenuCallback -- ^ A plain menu entry with an associated -- callback, which is triggered when the -- user selects the entry | SubMenu String Menu -- ^ A sub-menu, which is cascaded when the -- user selects the entry, allowing -- sub-menu entries to be selected type MenuCallback = IO () -- | Create a new pop-up menu for the /current window,/ attaching it to the -- given mouse button. A previously attached menu (if any), is detached before -- and won\'t receive callbacks anymore. -- -- It is illegal to call 'attachMenu' while any (sub-)menu is in use, i.e. -- popped up. -- -- /X Implementation Notes:/ If available, GLUT for X will take advantage of -- overlay planes for implementing pop-up menus. The use of overlay planes can -- eliminate display callbacks when pop-up menus are deactivated. The -- @SERVER_OVERLAY_VISUALS@ convention is used to determine if overlay visuals -- are available. attachMenu :: MonadIO m => MouseButton -> Menu -> m () attachMenu mouseButton menu = liftIO $ do win <- getCurrentWindow "attachMenu" let hook = MenuHook win mouseButton detachMenu hook unless (null (menuItems menu)) $ do (_, destructor) <- traverseMenu menu addToMenuTable hook destructor attachMenu_ mouseButton detachMenu :: MenuHook -> IO () detachMenu hook@(MenuHook _ mouseButton) = do maybeDestructor <- lookupInMenuTable hook case maybeDestructor of Nothing -> return () Just destructor -> do detachMenu_ mouseButton destructor deleteFromMenuTable hook traverseMenu :: Menu -> IO (MenuID, Destructor) traverseMenu menu = do let items = menuItems menu callbackArray = listArray (1, length items) (map makeCallback items) cb <- makeMenuFunc (\i -> callbackArray ! (fromIntegral i)) menuID <- glutCreateMenu cb maybe (return ()) (setMenuFont menuID) (menuFont menu) destructors <- zipWithM addMenuItem items [1..] let destructor = do sequence_ destructors glutDestroyMenu menuID freeHaskellFunPtr cb return (menuID, destructor) makeCallback :: MenuItem -> MenuCallback makeCallback (MenuEntry _ cb) = cb makeCallback _ = error "shouldn't receive a callback for submenus" addMenuItem :: MenuItem -> Value -> IO Destructor addMenuItem (MenuEntry s _) v = do addMenuEntry s v return $ glutRemoveMenuItem 1 addMenuItem (SubMenu s m) _ = do (menuID, destructor) <- saveExcursion (traverseMenu m) addSubMenu s menuID return $ do glutRemoveMenuItem 1 destructor -- Perform an action, saving/restoring the current menu around it saveExcursion :: IO a -> IO a saveExcursion act = do menuID <- get currentMenu returnValue <- act when (isRealMenu menuID) $ currentMenu $= menuID return returnValue -------------------------------------------------------------------------------- -- This seems to be a common Haskell hack nowadays: A plain old global variable -- with an associated mutator. Perhaps some language/library support is needed? {-# NOINLINE theMenuTable #-} theMenuTable :: IORef MenuTable theMenuTable = unsafePerformIO (newIORef emptyMenuTable) getMenuTable :: IO MenuTable getMenuTable = readIORef theMenuTable modifyMenuTable :: (MenuTable -> MenuTable) -> IO () modifyMenuTable = modifyIORef theMenuTable -------------------------------------------------------------------------------- -- To facilitate cleanup, we have to keep track how to destroy menus which are -- currently attached in a window to a mouse button. data MenuHook = MenuHook Window MouseButton deriving ( Eq, Ord ) type Destructor = IO () type MenuTable = M.Map MenuHook Destructor emptyMenuTable :: MenuTable emptyMenuTable = M.empty lookupInMenuTable :: MenuHook -> IO (Maybe Destructor) lookupInMenuTable callbackID = fmap (M.lookup callbackID) getMenuTable deleteFromMenuTable :: MenuHook -> IO () deleteFromMenuTable callbackID = modifyMenuTable (M.delete callbackID) addToMenuTable :: MenuHook -> Destructor -> IO () addToMenuTable callbackID funPtr = modifyMenuTable (M.insert callbackID funPtr) -------------------------------------------------------------------------------- type MenuID = CInt type Value = CInt -------------------------------------------------------------------------------- -- | Controls the /current menu./ If no menus exist or the previous /current -- menu/ was destroyed, a pseudo menu is returned. currentMenu :: StateVar MenuID currentMenu = makeStateVar glutGetMenu glutSetMenu -- | Returns 'True' if the given menu identifier refers to a real menu, not -- a pseudo one. isRealMenu :: MenuID -> Bool isRealMenu = (/= 0) -------------------------------------------------------------------------------- -- | Add a menu entry to the bottom of the /current menu./ The given string will -- be displayed for the newly added menu entry. If the menu entry is selected by -- the user, the menu\'s callback will be called passing the given value as the -- callback\'s parameter. addMenuEntry :: String -> Value -> IO () addMenuEntry name value = withCString name $ \n -> glutAddMenuEntry n value -- | Add a sub-menu trigger to the bottom of the /current menu./ The given -- string will be displayed for the newly added sub-menu trigger. If the -- sub-menu trigger is entered, the sub-menu specified by the given menu -- identifier will be cascaded, allowing sub-menu menu items to be selected. addSubMenu :: String -> MenuID -> IO () addSubMenu name menuID = withCString name $ \n -> glutAddSubMenu n menuID -------------------------------------------------------------------------------- {- UNUSED -- | Change the specified menu entry in the /current menu/ into a menu entry. -- The given position determines which menu item should be changed and must be -- between 1 (the topmost menu item) and -- 'Graphics.UI.GLUT.State.getNumMenuItems' inclusive. The menu item to change -- does not have to be a menu entry already. The given string will be displayed -- for the newly changed menu entry. The given value will be returned to the -- menu\'s callback if this menu entry is selected. foreign import CALLCONV unsafe "glutChangeToMenuEntry" glutChangeToMenuEntry :: Item -> CString -> Value -> IO () -- | Change the specified menu item in the /current menu/ into a sub-menu -- trigger. The given position determines which menu item should be changed and -- must be between 1 and 'Graphics.UI.GLUT.State.getNumMenuItems' inclusive. The -- menu item to change does not have to be a sub-menu trigger already. The -- given name will be displayed for the newly changed sub-menu trigger. The -- given menu identifier names the sub-menu to cascade from the newly added -- sub-menu trigger. foreign import CALLCONV unsafe "glutChangeToSubMenu" glutChangeToSubMenu :: Item -> CString -> MenuID -> IO () -} -------------------------------------------------------------------------------- -- | Attach a mouse button for the /current window/ to the identifier of the -- /current menu./ By attaching a menu identifier to a button, the named menu -- will be popped up when the user presses the specified button. Note that the -- menu is attached to the button by identifier, not by reference. attachMenu_ :: MouseButton -> IO () attachMenu_ = glutAttachMenu . marshalMouseButton -- | Detach an attached mouse button from the /current window./ detachMenu_ :: MouseButton -> IO () detachMenu_ = glutDetachMenu . marshalMouseButton -------------------------------------------------------------------------------- -- | Contains the number of menu items in the /current menu./ numMenuItems :: GettableStateVar Int numMenuItems = makeGettableStateVar $ simpleGet fromIntegral glut_MENU_NUM_ITEMS -------------------------------------------------------------------------------- setMenuFont :: MenuID -> BitmapFont -> IO () setMenuFont menuID font = glutSetMenuFont menuID =<< marshalBitmapFont font GLUT-2.7.0.16/src/Graphics/UI/GLUT/Objects.hs0000644000000000000000000002025013255126367016263 0ustar0000000000000000-------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Objects -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- GLUT includes a number of routines for generating easily recognizable 3D -- geometric objects. These routines reflect functionality available in the -- @aux@ toolkit described in the /OpenGL Programmer\'s Guide/ and are included -- in GLUT to allow the construction of simple GLUT programs that render -- recognizable objects. These routines can be implemented as pure OpenGL -- rendering routines. The routines do not generate display lists for the -- objects they create. The routines generate normals appropriate for lighting -- but do not generate texture coordinates (except for the solid teapot, teacup -- and teaspoon). If VBOs should be used instead of the fixed function pipeline, -- specify at least one of the attribute locations -- 'Graphics.UI.GLUT.State.vertexAttribCoord3' or -- 'Graphics.UI.GLUT.State.vertexAttribNormal'. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Objects ( -- * Rendering flavour Flavour(..), -- * Object description Object(..), -- * Type synonyms Sides, Rings, NumLevels, -- * Rendering renderObject ) where import Control.Monad.IO.Class ( MonadIO(..) ) import Foreign.C.Types ( CInt ) import Foreign.Marshal.Utils ( with ) import Foreign.Ptr ( Ptr, castPtr ) import Graphics.Rendering.OpenGL ( Height, Radius, Slices, Stacks, Vertex3(..), GLdouble, GLint ) import Graphics.UI.GLUT.Raw -------------------------------------------------------------------------------- -- | Flavour of object rendering data Flavour = -- | Object is rendered as a solid with shading and surface normals. Solid | -- | Object is rendered as a wireframe without surface normals. Wireframe deriving ( Eq, Ord, Show ) -------------------------------------------------------------------------------- -- | GLUT offers five types of objects: -- -- * The five Platonic solids, see -- . -- -- * A rhombic dodecahedron, see -- . -- -- * Approximations to rounded objects. -- -- * The classic teaset modeled by Martin Newell in 1975. Both surface normals -- and texture coordinates for the teaset are generated. -- -- * A Sierpinski sponge, see -- . data Object = -- | A cube centered at the modeling coordinates origin with sides of the -- given length. Cube Height | -- | A dodecahedron (12-sided regular solid) centered at the modeling -- coordinates origin with a radius of @sqrt 3@. Dodecahedron | -- | A icosahedron (20-sided regular solid) centered at the modeling -- coordinates origin with a radius of 1.0. Icosahedron | -- | Render a solid octahedron (8-sided regular solid) centered at the -- modeling coordinates origin with a radius of 1.0. Octahedron | -- | Render a solid tetrahedron (4-sided regular solid) centered at the -- modeling coordinates origin with a radius of @sqrt 3@. Tetrahedron | -- | (/freeglut only/) A rhombic dodecahedron whose corners are at most a -- distance of one from the origin. The rhombic dodecahedron has faces -- which are identical rhombi, but which have some vertices at which three -- faces meet and some vertices at which four faces meet. The length of -- each side is @(sqrt 3)\/2@. Vertices at which four faces meet are found -- at @(0, 0, +\/-1)@ and @(+\/-(sqrt 2)\/2, +\/-(sqrt 2)\/2, 0)@. RhombicDodecahedron | -- | A sphere centered at the modeling coordinates origin of the specified -- radius. The sphere is subdivided around the Z axis into slices -- (similar to lines of longitude) and along the Z axis into stacks -- (similar to lines of latitude). Sphere' Radius Slices Stacks | -- | A cone oriented along the Z axis. The base of the cone is placed at Z -- = 0, and the top at Z = the given height. The cone is subdivided -- around the Z axis into slices, and along the Z axis into stacks. Cone Radius Height Slices Stacks | -- |(/freeglut only/) A cylinder oriented along the Z axis. The base of the -- cylinder is placed at Z = 0, and the top at Z = the given height. The -- cylinder is subdivided around the Z axis into slices, and along the Z -- axis into stacks. Cylinder' Radius Height Slices Stacks | -- | A torus (doughnut) centered at the modeling coordinates origin -- whose axis is aligned with the Z axis. The torus is described by its -- inner and outer radius, the number of sides for each radial section, -- and the number of radial divisions (rings). Torus Radius Radius Sides Rings | -- | A teapot with a given relative size. Teapot Height | -- |(/freeglut only/) A teacup with a given relative size. Teacup Height | -- |(/freeglut only/) A teaspoon with a given relative size. Teaspoon Height | -- |(/freeglut only/) A Sierpinski sponge of a given level, where a level -- 0 sponge is the same as a 'Tetrahedron'. SierpinskiSponge NumLevels deriving ( Eq, Ord, Show ) -------------------------------------------------------------------------------- type Sides = GLint type Rings = GLint type NumLevels = GLint -------------------------------------------------------------------------------- -- | Render an object in the given flavour. renderObject :: MonadIO m => Flavour -> Object -> m () renderObject Solid (Cube h) = glutSolidCube h renderObject Wireframe (Cube h) = glutWireCube h renderObject Solid Dodecahedron = glutSolidDodecahedron renderObject Wireframe Dodecahedron = glutWireDodecahedron renderObject Solid Icosahedron = glutSolidIcosahedron renderObject Wireframe Icosahedron = glutWireIcosahedron renderObject Solid Octahedron = glutSolidOctahedron renderObject Wireframe Octahedron = glutWireOctahedron renderObject Solid Tetrahedron = glutSolidTetrahedron renderObject Wireframe Tetrahedron = glutWireTetrahedron renderObject Solid RhombicDodecahedron = glutSolidRhombicDodecahedron renderObject Wireframe RhombicDodecahedron = glutWireRhombicDodecahedron renderObject Solid (Sphere' r s t) = glutSolidSphere r s t renderObject Wireframe (Sphere' r s t) = glutWireSphere r s t renderObject Solid (Cone r h s t) = glutSolidCone r h s t renderObject Wireframe (Cone r h s t) = glutWireCone r h s t renderObject Solid (Cylinder' r h s t) = glutSolidCylinder r h s t renderObject Wireframe (Cylinder' r h s t) = glutWireCylinder r h s t renderObject Solid (Torus i o s r) = glutSolidTorus i o s r renderObject Wireframe (Torus i o s r) = glutWireTorus i o s r renderObject Solid (Teapot h) = glutSolidTeapot h renderObject Wireframe (Teapot h) = glutWireTeapot h renderObject Solid (Teacup h) = glutSolidTeacup h renderObject Wireframe (Teacup h) = glutWireTeacup h renderObject Solid (Teaspoon h) = glutSolidTeaspoon h renderObject Wireframe (Teaspoon h) = glutWireTeaspoon h renderObject Solid (SierpinskiSponge n) = solidSierpinskiSponge n renderObject Wireframe (SierpinskiSponge n) = wireSierpinskiSponge n -------------------------------------------------------------------------------- solidSierpinskiSponge :: MonadIO m => NumLevels -> m () solidSierpinskiSponge = sierpinskiSponge glutSolidSierpinskiSponge wireSierpinskiSponge :: MonadIO m => NumLevels -> m () wireSierpinskiSponge = sierpinskiSponge glutWireSierpinskiSponge -- for consistency, we hide the offset and scale on the Haskell side sierpinskiSponge :: MonadIO m => (CInt -> Ptr GLdouble -> Height -> IO ()) -> NumLevels -> m () sierpinskiSponge f n = liftIO $ with (Vertex3 0 0 0) $ \offsetBuf -> f (fromIntegral n) ((castPtr :: Ptr (Vertex3 GLdouble) -> Ptr GLdouble) offsetBuf) 1 GLUT-2.7.0.16/src/Graphics/UI/GLUT/Overlay.hs0000644000000000000000000001573013255126367016322 0ustar0000000000000000-------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Overlay -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- When overlay hardware is available, GLUT provides a set of routines for -- establishing, using, and removing an overlay for GLUT windows. When an -- overlay is established, a separate OpenGL context is also established. A -- window\'s overlay OpenGL state is kept distinct from the normal planes\' -- OpenGL state. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Overlay ( -- * Overlay creation and destruction hasOverlay, overlayPossible, -- * Showing and hiding an overlay overlayVisible, -- * Changing the /layer in use/ Layer(..), layerInUse, -- * Re-displaying postOverlayRedisplay ) where import Control.Monad.IO.Class ( MonadIO(..) ) import Data.StateVar ( GettableStateVar, makeGettableStateVar , SettableStateVar, makeSettableStateVar , StateVar, makeStateVar ) import Graphics.Rendering.OpenGL ( GLenum ) import Graphics.UI.GLUT.QueryUtils import Graphics.UI.GLUT.Raw import Graphics.UI.GLUT.Types -------------------------------------------------------------------------------- -- | Controls the overlay for the /current window/. The requested display mode -- for the overlay is determined by the /initial display mode/. -- 'overlayPossible' can be used to determine if an overlay is possible for the -- /current window/ with the current /initial display mode/. Do not attempt to -- establish an overlay when one is not possible; GLUT will terminate the -- program. -- -- When 'hasOverlay' is set to 'True' when an overlay already exists, the -- existing overlay is first removed, and then a new overlay is established. The -- state of the old overlay\'s OpenGL context is discarded. Implicitly, the -- window\'s /layer in use/ changes to the overlay immediately after the overlay -- is established. -- -- The initial display state of an overlay is shown, however the overlay is only -- actually shown if the overlay\'s window is shown. -- -- Setting 'hasOverlay' to 'False' is safe even if no overlay is currently -- established, nothing happens in this case. Implicitly, the window\'s /layer -- in use/ changes to the normal plane immediately once the overlay is removed. -- -- If the program intends to re-establish the overlay later, it is typically -- faster and less resource intensive to use 'overlayVisible' to simply change -- the display status of the overlay. -- -- /X Implementation Notes:/ GLUT for X uses the @SERVER_OVERLAY_VISUALS@ -- convention to determine if overlay visuals are available. While the -- convention allows for opaque overlays (no transparency) and overlays with the -- transparency specified as a bitmask, GLUT overlay management only provides -- access to transparent pixel overlays. -- -- Until RGBA overlays are better understood, GLUT only supports color index -- overlays. hasOverlay :: StateVar Bool hasOverlay = makeStateVar getHasOverlay setHasOverlay setHasOverlay :: Bool -> IO () setHasOverlay False = glutRemoveOverlay setHasOverlay True = glutEstablishOverlay getHasOverlay :: IO Bool getHasOverlay = layerGet (/= 0) glut_HAS_OVERLAY -------------------------------------------------------------------------------- -- | Contains 'True' if an overlay could be established for the /current window/ -- given the current /initial display mode/. If it contains 'False', setting -- 'hasOverlay' will fail with a fatal error. overlayPossible :: GettableStateVar Bool overlayPossible = makeGettableStateVar $ layerGet (/= 0) glut_OVERLAY_POSSIBLE -------------------------------------------------------------------------------- -- | Controls the visibility of the overlay of the /current window/. -- -- The effect of showing or hiding an overlay takes place immediately. Note that -- setting 'overlayVisible' to 'True' will not actually display the overlay -- unless the window is also shown (and even a shown window may be obscured by -- other windows, thereby obscuring the overlay). It is typically faster and -- less resource intensive to use the routines below to control the display -- status of an overlay as opposed to removing and re-establishing the overlay. overlayVisible :: SettableStateVar Bool overlayVisible = makeSettableStateVar $ \flag -> if flag then glutShowOverlay else glutHideOverlay -------------------------------------------------------------------------------- -- | The /layer in use/. data Layer = Normal -- ^ The normal plane. | Overlay -- ^ The overlay. deriving ( Eq, Ord, Show ) marshalLayer :: Layer -> GLenum marshalLayer x = case x of Normal -> glut_NORMAL Overlay -> glut_OVERLAY unmarshalLayer :: GLenum -> Layer unmarshalLayer x | x == glut_NORMAL = Normal | x == glut_OVERLAY = Overlay | otherwise = error ("unmarshalLayer: illegal value " ++ show x) -------------------------------------------------------------------------------- -- | Controls the per-window /layer in use/ for the /current window/, which can -- either be the normal plane or the overlay. Selecting the overlay should only -- be done if an overlay exists, however windows without an overlay may still -- set the /layer in use/ to 'Normal'. OpenGL commands for the window are -- directed to the current /layer in use/. layerInUse :: StateVar Layer layerInUse = makeStateVar getLayerInUse setLayerInUse setLayerInUse :: Layer -> IO () setLayerInUse = glutUseLayer . marshalLayer getLayerInUse :: IO Layer getLayerInUse = layerGet (unmarshalLayer . fromIntegral) glut_LAYER_IN_USE -------------------------------------------------------------------------------- -- | Mark the overlay of the given window (or the /current window/, if none is -- supplied) as needing to be redisplayed. The next iteration through -- 'Graphics.UI.GLUT.Begin.mainLoop', the window\'s overlay display callback -- (or simply the display callback if no overlay display callback is registered) -- will be called to redisplay the window\'s overlay plane. Multiple calls to -- 'postOverlayRedisplay' before the next display callback opportunity (or -- overlay display callback opportunity if one is registered) generate only a -- single redisplay. 'postOverlayRedisplay' may be called within a window\'s -- display or overlay display callback to re-mark that window for redisplay. -- -- Logically, overlay damage notification for a window is treated as a -- 'postOverlayRedisplay' on the damaged window. Unlike damage reported by the -- window system, 'postOverlayRedisplay' will not set to true the overlay\'s -- damaged status (see 'Graphics.UI.GLUT.State.damaged'). -- -- Also, see 'Graphics.UI.GLUT.Window.postRedisplay'. postOverlayRedisplay :: MonadIO m => Maybe Window -> m () postOverlayRedisplay = maybe glutPostOverlayRedisplay (\(Window win) -> glutPostWindowOverlayRedisplay win) GLUT-2.7.0.16/src/Graphics/UI/GLUT/State.hs0000644000000000000000000003757613255126367015775 0ustar0000000000000000-------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.State -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- GLUT maintains a considerable amount of programmer visible state. Some (but -- not all) of this state may be directly retrieved. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.State ( -- * State of all windows windowBorderWidth, windowHeaderHeight, skipStaleMotionEvents, -- * State of the /current window/ -- ** Framebuffer state rgba, BufferDepth, rgbaBufferDepths, colorBufferDepth, doubleBuffered, stereo, accumBufferDepths, depthBufferDepth, stencilBufferDepth, SampleCount, sampleCount, formatID, -- ** Full screen state fullScreenMode, -- ** Object rendering state geometryVisualizeNormals, -- ** Vertex attribute state vertexAttribCoord3, vertexAttribNormal, vertexAttribTexCoord2, -- ** Layer state damaged, -- * Timing elapsedTime, -- * Device information -- $DeviceInformation screenSize, screenSizeMM, hasKeyboard, ButtonCount, numMouseButtons, numSpaceballButtons, DialCount, numDialsAndButtons, numTabletButtons, AxisCount, PollRate, joystickInfo, supportedNumAuxBuffers, supportedSamplesPerPixel, -- * GLUT information glutVersion, initState ) where import Control.Monad ( unless ) import Data.StateVar ( GettableStateVar, makeGettableStateVar , SettableStateVar, makeSettableStateVar , StateVar, makeStateVar ) import Foreign.C.Types ( CInt ) import Foreign.Marshal.Alloc ( alloca ) import Foreign.Marshal.Array ( peekArray ) import Foreign.Storable ( peek ) import Graphics.Rendering.OpenGL ( AttribLocation(..), Size(..), GLenum, GLint ) import Graphics.UI.GLUT.Overlay import Graphics.UI.GLUT.QueryUtils import Graphics.UI.GLUT.Raw import Graphics.UI.GLUT.Window -------------------------------------------------------------------------------- -- | Contains 'True' when the current layer of the /current window/ is in RGBA -- mode, 'False' means color index mode. rgba :: GettableStateVar Bool rgba = makeGettableStateVar$ simpleGet i2b glut_WINDOW_RGBA -- | Bit depth of a buffer type BufferDepth = Int -- | Contains the number of red, green, blue, and alpha bits in the color buffer -- of the /current window\'s/ current layer (0 in color index mode). rgbaBufferDepths :: GettableStateVar (BufferDepth, BufferDepth, BufferDepth, BufferDepth) rgbaBufferDepths = makeGettableStateVar $ do r <- simpleGet fromIntegral glut_WINDOW_RED_SIZE g <- simpleGet fromIntegral glut_WINDOW_GREEN_SIZE b <- simpleGet fromIntegral glut_WINDOW_BLUE_SIZE a <- simpleGet fromIntegral glut_WINDOW_ALPHA_SIZE return (r, g, b, a) -- | Contains the total number of bits in the color buffer of the /current -- window\'s/ current layer. For an RGBA layer, this is the sum of the red, -- green, blue, and alpha bits. For an color index layer, this is the number -- of bits of the color indexes. colorBufferDepth :: GettableStateVar BufferDepth colorBufferDepth = makeGettableStateVar $ simpleGet fromIntegral glut_WINDOW_BUFFER_SIZE -- | Contains 'True' when the current layer of the /current window/ is double -- buffered, 'False' otherwise. doubleBuffered :: GettableStateVar Bool doubleBuffered = makeGettableStateVar $ simpleGet i2b glut_WINDOW_DOUBLEBUFFER -- | Contains 'True' when the current layer of the /current window/ is stereo, -- 'False' otherwise. stereo :: GettableStateVar Bool stereo = makeGettableStateVar $ simpleGet i2b glut_WINDOW_STEREO -- | Contains the number of red, green, blue, and alpha bits in the accumulation -- buffer of the /current window\'s/ current layer (0 in color index mode). accumBufferDepths :: GettableStateVar (BufferDepth, BufferDepth, BufferDepth, BufferDepth) accumBufferDepths = makeGettableStateVar $ do r <- simpleGet fromIntegral glut_WINDOW_ACCUM_RED_SIZE g <- simpleGet fromIntegral glut_WINDOW_ACCUM_GREEN_SIZE b <- simpleGet fromIntegral glut_WINDOW_ACCUM_BLUE_SIZE a <- simpleGet fromIntegral glut_WINDOW_ACCUM_ALPHA_SIZE return (r, g, b, a) -- | Contains the number of bits in the depth buffer of the /current window\'s/ -- current layer. depthBufferDepth :: GettableStateVar BufferDepth depthBufferDepth = makeGettableStateVar $ simpleGet fromIntegral glut_WINDOW_DEPTH_SIZE -- | Contains the number of bits in the stencil buffer of the /current -- window\'s/ current layer. stencilBufferDepth :: GettableStateVar BufferDepth stencilBufferDepth = makeGettableStateVar $ simpleGet fromIntegral glut_WINDOW_STENCIL_SIZE -- | Number of samples for multisampling type SampleCount = Int -- | Contains the number of samples for multisampling for the /current window./ sampleCount :: GettableStateVar SampleCount sampleCount = makeGettableStateVar $ simpleGet fromIntegral glut_WINDOW_NUM_SAMPLES -- | Contains the window system dependent format ID for the current layer of the -- /current window/. On X11 GLUT implementations, this is the X visual ID. On -- Win32 GLUT implementations, this is the Win32 Pixel Format Descriptor number. -- This value is returned for debugging, benchmarking, and testing ease. formatID :: GettableStateVar Int formatID = makeGettableStateVar $ simpleGet fromIntegral glut_WINDOW_FORMAT_ID -------------------------------------------------------------------------------- -- | (/freeglut only/) Contains 'True' if the /current window/ is in full screen -- mode, 'False' otherwise. fullScreenMode :: StateVar Bool fullScreenMode = makeStateVar getFullScreenMode setFullScreenMode getFullScreenMode :: IO Bool getFullScreenMode = simpleGet i2b glut_FULL_SCREEN setFullScreenMode :: Bool -> IO () setFullScreenMode newMode = do oldMode <- getFullScreenMode unless (newMode == oldMode) fullScreenToggle -------------------------------------------------------------------------------- -- | (/freeglut only/) Controls if vectors representing the normals should be -- drawn, too, when objects are drawn. geometryVisualizeNormals :: StateVar Bool geometryVisualizeNormals = makeStateVar (simpleGet i2b glut_GEOMETRY_VISUALIZE_NORMALS) (glutSetOption glut_GEOMETRY_VISUALIZE_NORMALS . b2i) -------------------------------------------------------------------------------- -- | (/freeglut only/) If 'vertexAttribCoord3' and 'vertexAttribNormal' both -- contain 'Nothing', the fixed function pipeline is used to draw -- objects. Otherwise VBOs are used and the coordinates are passed via 'Just' -- this attribute location (for a vec3). vertexAttribCoord3 :: SettableStateVar (Maybe AttribLocation) vertexAttribCoord3 = setVertexAttribWith glutSetVertexAttribCoord3 setVertexAttribWith :: (GLint -> IO ()) -> SettableStateVar (Maybe AttribLocation) setVertexAttribWith f = makeSettableStateVar $ f . getLocation where getLocation = maybe (-1) (\(AttribLocation l) -> fromIntegral l) -- | (/freeglut only/) If 'vertexAttribCoord3' and 'vertexAttribNormal' both -- contain 'Nothing', the fixed function pipeline is used to draw -- objects. Otherwise VBOs are used and the normals are passed via 'Just' this -- attribute location (for a vec3). vertexAttribNormal :: SettableStateVar (Maybe AttribLocation) vertexAttribNormal = setVertexAttribWith glutSetVertexAttribNormal -- | (/freeglut only/) If VBOs are used to draw objects (controlled via -- 'vertexAttribCoord3' and 'vertexAttribNormal'), the texture coordinates are -- passed via 'Just' this attribute location (for a vec2). vertexAttribTexCoord2 :: SettableStateVar (Maybe AttribLocation) vertexAttribTexCoord2 = setVertexAttribWith glutSetVertexAttribTexCoord2 -------------------------------------------------------------------------------- -- | Contains the number of milliseconds since -- 'Graphics.UI.GLUT.Initialization.initialize' was called. elapsedTime :: GettableStateVar Int elapsedTime = makeGettableStateVar $ simpleGet fromIntegral glut_ELAPSED_TIME -------------------------------------------------------------------------------- -- | Contains 'True' if the given plane of the /current window/ has been -- damaged (by window system activity) since the last display callback was -- triggered. Calling 'Graphics.UI.GLUT.Window.postRedisplay' or -- 'Graphics.UI.GLUT.Overlay.postOverlayRedisplay' will not set this 'True'. damaged :: Layer -> GettableStateVar Bool damaged l = makeGettableStateVar $ layerGet isDamaged (marshalDamagedLayer l) where isDamaged d = d /= 0 && d /= -1 marshalDamagedLayer x = case x of Normal -> glut_NORMAL_DAMAGED Overlay -> glut_OVERLAY_DAMAGED -------------------------------------------------------------------------------- -- $DeviceInformation -- If a device is not available, the following state variables contain -- 'Nothing', otherwise they return 'Just' the specific device information. -- Only a screen is always assumed. -------------------------------------------------------------------------------- -- | The size of the screen in pixels. screenSize :: GettableStateVar Size screenSize = makeGettableStateVar $ do wpx <- simpleGet fromIntegral glut_SCREEN_WIDTH hpx <- simpleGet fromIntegral glut_SCREEN_HEIGHT return $ Size wpx hpx -- | The size of the screen in millimeters. screenSizeMM :: GettableStateVar Size screenSizeMM = makeGettableStateVar $ do wmm <- simpleGet fromIntegral glut_SCREEN_WIDTH_MM hmm <- simpleGet fromIntegral glut_SCREEN_HEIGHT_MM return $ Size wmm hmm -------------------------------------------------------------------------------- -- | Contains 'True' if a keyboard is present, 'False' otherwise. hasKeyboard :: GettableStateVar Bool hasKeyboard = makeGettableStateVar $ deviceGet i2b glut_HAS_KEYBOARD -------------------------------------------------------------------------------- -- | Number of buttons of an input device type ButtonCount = Int -- | Contains 'Just' the number of buttons of an attached mouse or 'Nothing' if -- there is none. numMouseButtons :: GettableStateVar (Maybe ButtonCount) numMouseButtons = getDeviceInfo glut_HAS_MOUSE $ deviceGet fromIntegral glut_NUM_MOUSE_BUTTONS -------------------------------------------------------------------------------- -- | Contains 'Just' the number of buttons of the attached Spaceball or 'Nothing' -- if there is none. numSpaceballButtons :: GettableStateVar (Maybe ButtonCount) numSpaceballButtons = getDeviceInfo glut_HAS_SPACEBALL $ deviceGet fromIntegral glut_NUM_SPACEBALL_BUTTONS -------------------------------------------------------------------------------- -- | Number of dials of a dial and button box type DialCount = Int -- | Contains 'Just' the number of dials and buttons of an attached dial & -- button box or 'Nothing' if there is none. numDialsAndButtons :: GettableStateVar (Maybe (DialCount, ButtonCount)) numDialsAndButtons = getDeviceInfo glut_HAS_DIAL_AND_BUTTON_BOX $ do d <- deviceGet fromIntegral glut_NUM_DIALS b <- deviceGet fromIntegral glut_NUM_BUTTON_BOX_BUTTONS return (d, b) -------------------------------------------------------------------------------- -- | Contains 'Just' the number of buttons of an attached tablet or 'Nothing' if -- there is none. numTabletButtons :: GettableStateVar (Maybe ButtonCount) numTabletButtons = getDeviceInfo glut_HAS_TABLET $ deviceGet fromIntegral glut_NUM_TABLET_BUTTONS -------------------------------------------------------------------------------- -- | Number of axes of a joystick type AxisCount = Int -- | The a rate at which a joystick is polled (in milliseconds) type PollRate = Int -- | Contains 'Just' the number of buttons of an attached joystick, the number -- of joystick axes, and the rate at which the joystick is polled. Contains -- 'Nothing' if there is no joystick attached. joystickInfo :: GettableStateVar (Maybe (ButtonCount, PollRate, AxisCount)) joystickInfo = getDeviceInfo glut_HAS_JOYSTICK $ do b <- deviceGet fromIntegral glut_JOYSTICK_BUTTONS a <- deviceGet fromIntegral glut_JOYSTICK_AXES r <- deviceGet fromIntegral glut_JOYSTICK_POLL_RATE return (b, a, r) ----------------------------------------------------------------------------- -- | (/freeglut only/) Contains a list of the number of auxiliary buffers -- supported, in increasing order. supportedNumAuxBuffers :: GettableStateVar [Int] supportedNumAuxBuffers = getModeValues glut_AUX -- | (/freeglut only/) Contains a list of the number of samples per pixel -- supported for multisampling, in increasing order. supportedSamplesPerPixel :: GettableStateVar [SampleCount] supportedSamplesPerPixel = getModeValues (fromIntegral glut_MULTISAMPLE) getModeValues :: Integral a => GLenum -> GettableStateVar [a] getModeValues what = makeGettableStateVar $ alloca $ \sizeBuffer -> do valuesBuffer <- glutGetModeValues what sizeBuffer size <- peek sizeBuffer fmap (map fromIntegral) $ peekArray (fromIntegral size) valuesBuffer -------------------------------------------------------------------------------- -- Convenience (un-)marshalers i2b :: CInt -> Bool i2b = (/= 0) b2i :: Bool -> CInt b2i False = 0 b2i True = 1 -------------------------------------------------------------------------------- getDeviceInfo :: GLenum -> IO a -> GettableStateVar (Maybe a) getDeviceInfo dev act = makeGettableStateVar $ do hasDevice <- deviceGet i2b dev if hasDevice then fmap Just act else return Nothing ----------------------------------------------------------------------------- -- | Contains version of GLUT in the form of -- @/flavour/ /major/./minor/./patchlevel/@, where @/flavour/@ is one of -- @GLUT@, @freeglut@ or @OpenGLUT@. glutVersion :: GettableStateVar String glutVersion = makeGettableStateVar $ do let isGLUT = not `fmap` isKnown "glutSetOption" isFreeglut = not `fmap` isKnown "glutSetWindowStayOnTop" showVersionPart x = shows (x `mod` 100) showVersion v = showVersionPart (v `div` 10000) . showChar '.' . showVersionPart (v `div` 100) . showChar '.' . showVersionPart v g <- isGLUT if g then return "GLUT 3.7" -- ToDo: just guessing else do f <- isFreeglut v <- simpleGet id glut_VERSION let prefix = if f then "freeglut" else "OpenGLUT" return $ showString prefix . showChar ' ' . showVersion v $ "" ----------------------------------------------------------------------------- -- | (/freeglut only/) Contains the thickness of the sizing border around the -- perimeter of a window that can be resized, in pixels. windowBorderWidth :: GettableStateVar Int windowBorderWidth = makeGettableStateVar (simpleGet fromIntegral glut_WINDOW_BORDER_WIDTH) ----------------------------------------------------------------------------- -- | (/freeglut only/) Contains the height of the header\/caption area of a -- window in pixels. windowHeaderHeight :: GettableStateVar Int windowHeaderHeight = makeGettableStateVar (simpleGet fromIntegral glut_WINDOW_HEADER_HEIGHT) ----------------------------------------------------------------------------- -- | (/freeglut on X11 only/) Controls if all but the last motion event should -- be discarded. skipStaleMotionEvents :: StateVar Bool skipStaleMotionEvents = makeStateVar (simpleGet i2b glut_SKIP_STALE_MOTION_EVENTS) (glutSetOption glut_SKIP_STALE_MOTION_EVENTS . b2i) ----------------------------------------------------------------------------- -- | (/freeglut only/) Contains 'True' if GLUT has been initialized -- with 'Graphics.UI.GLUT.Initialization.initialize' or -- 'Graphics.UI.GLUT.Initialization.getArgsAndInitialize' has and not yet -- been de-initialized with 'Graphics.UI.GLUT.Initialization.exit'. Contains -- 'False' otherwise. initState :: GettableStateVar Bool initState = makeGettableStateVar$ simpleGet i2b glut_INIT_STATE GLUT-2.7.0.16/src/Graphics/UI/GLUT/Window.hs0000644000000000000000000005070613255126367016152 0ustar0000000000000000-------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Window -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- GLUT supports two types of windows: top-level windows and subwindows. Both -- types support OpenGL rendering and GLUT callbacks. There is a single -- identifier space for both types of windows. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Window ( -- * Window identifiers Window, -- * Creating and destroying (sub-)windows -- $CreatingAndDestroyingSubWindows createWindow, createSubWindow, destroyWindow, parentWindow, numSubWindows, -- * Manipulating the /current window/ currentWindow, -- * Re-displaying and double buffer management postRedisplay, swapBuffers, -- * Changing the window geometry -- $ChangingTheWindowGeometry windowPosition, windowSize, fullScreen, fullScreenToggle, leaveFullScreen, -- * Manipulating the stacking order -- $ManipulatingTheStackingOrder pushWindow, popWindow, -- * Managing a window\'s display status WindowStatus(..), windowStatus, -- * Changing the window\/icon title -- $ChangingTheWindowIconTitle windowTitle, iconTitle, -- * Cursor management Cursor(..), cursor, pointerPosition ) where import Control.Monad.IO.Class ( MonadIO(..) ) import Data.StateVar ( GettableStateVar, makeGettableStateVar , SettableStateVar, makeSettableStateVar , StateVar, makeStateVar ) import Foreign.C.String ( withCString ) import Foreign.C.Types ( CInt ) import Graphics.Rendering.OpenGL ( Position(..), Size(..) ) import Graphics.UI.GLUT.QueryUtils import Graphics.UI.GLUT.Raw import Graphics.UI.GLUT.Types -------------------------------------------------------------------------------- -- $CreatingAndDestroyingSubWindows -- Each created window has a unique associated OpenGL context. State changes to -- a window\'s associated OpenGL context can be done immediately after the -- window is created. -- -- The /display state/ of a window is initially for the window to be shown. But -- the window\'s /display state/ is not actually acted upon until -- 'Graphics.UI.GLUT.Begin.mainLoop' is entered. This means until -- 'Graphics.UI.GLUT.Begin.mainLoop' is called, rendering to a created window is -- ineffective because the window can not yet be displayed. -- -- The value returned by 'createWindow' and 'createSubWindow' is a unique -- identifier for the window, which can be used with 'currentWindow'. -- | Create a top-level window. The given name will be provided to the window -- system as the window\'s name. The intent is that the window system will label -- the window with the name.Implicitly, the /current window/ is set to the newly -- created window. -- -- /X Implementation Notes:/ The proper X Inter-Client Communication Conventions -- Manual (ICCCM) top-level properties are established. The @WM_COMMAND@ -- property that lists the command line used to invoke the GLUT program is only -- established for the first window created. createWindow :: MonadIO m => String -- ^ The window name -> m Window -- ^ The identifier for the newly created window createWindow name = liftIO $ fmap Window $ withCString name glutCreateWindow -------------------------------------------------------------------------------- -- | Create a subwindow of the identified window with the given relative -- position and size. Implicitly, the /current window/ is set to the -- newly created subwindow. Subwindows can be nested arbitrarily deep. createSubWindow :: MonadIO m => Window -- ^ Identifier of the subwindow\'s parent window. -> Position -- ^ Window position in pixels relative to parent window\'s -- origin. -> Size -- ^ Window size in pixels -> m Window -- ^ The identifier for the newly created subwindow createSubWindow (Window win) (Position x y) (Size w h) = do s <- glutCreateSubWindow win (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h) return $ Window s -------------------------------------------------------------------------------- -- | Contains the /current window\'s/ parent. If the /current window/ is a -- top-level window, 'Nothing' is returned. parentWindow :: GettableStateVar (Maybe Window) parentWindow = makeGettableStateVar $ getWindow (simpleGet Window glut_WINDOW_PARENT) -------------------------------------------------------------------------------- -- | Contains the number of subwindows the /current window/ has, not counting -- children of children. numSubWindows :: GettableStateVar Int numSubWindows = makeGettableStateVar $ simpleGet fromIntegral glut_WINDOW_NUM_CHILDREN -------------------------------------------------------------------------------- -- | Destroy the specified window and the window\'s associated OpenGL context, -- logical colormap (if the window is color index), and overlay and related -- state (if an overlay has been established). Any subwindows of the destroyed -- window are also destroyed by 'destroyWindow'. If the specified window was the -- /current window/, the /current window/ becomes invalid ('currentWindow' will -- contain 'Nothing'). destroyWindow :: MonadIO m => Window -> m () destroyWindow (Window win) = glutDestroyWindow win -------------------------------------------------------------------------------- -- | Controls the /current window/. It does /not/ affect the /layer in use/ for -- the window; this is done using 'Graphics.UI.GLUT.Overlay.layerInUse'. -- Contains 'Nothing' if no windows exist or the previously /current window/ was -- destroyed. Setting the /current window/ to 'Nothing' is a no-op. currentWindow :: StateVar (Maybe Window) currentWindow = makeStateVar (getWindow (fmap Window glutGetWindow)) (maybe (return ()) (\(Window win) -> glutSetWindow win)) getWindow :: IO Window -> IO (Maybe Window) getWindow act = do win <- act return $ if win == Window 0 then Nothing else Just win -------------------------------------------------------------------------------- -- | Mark the normal plane of given window (or the /current window/, if none -- is supplied) as needing to be redisplayed. The next iteration through -- 'Graphics.UI.GLUT.Begin.mainLoop', the window\'s display callback will be -- called to redisplay the window\'s normal plane. Multiple calls to -- 'postRedisplay' before the next display callback opportunity generates only a -- single redisplay callback. 'postRedisplay' may be called within a window\'s -- display or overlay display callback to re-mark that window for redisplay. -- -- Logically, normal plane damage notification for a window is treated as a -- 'postRedisplay' on the damaged window. Unlike damage reported by the window -- system, 'postRedisplay' will /not/ set to true the normal plane\'s damaged -- status (see 'Graphics.UI.GLUT.State.damaged'). -- -- Also, see 'Graphics.UI.GLUT.Overlay.postOverlayRedisplay'. postRedisplay :: MonadIO m => Maybe Window -> m () postRedisplay = maybe glutPostRedisplay (\(Window win) -> glutPostWindowRedisplay win) -- | Mark the normal plane of the given window as needing to be redisplayed, -- otherwise the same as 'postRedisplay'. -- -- The advantage of this routine is that it saves the cost of using -- 'currentWindow' (entailing an expensive OpenGL context switch), which is -- particularly useful when multiple windows need redisplays posted at the same -- time. -------------------------------------------------------------------------------- -- | Perform a buffer swap on the /layer in use/ for the /current window/. -- Specifically, 'swapBuffers' promotes the contents of the back buffer of the -- /layer in use/ of the /current window/ to become the contents of the front -- buffer. The contents of the back buffer then become undefined. The update -- typically takes place during the vertical retrace of the monitor, rather than -- immediately after 'swapBuffers' is called. -- -- An implicit 'Graphics.Rendering.OpenGL.GL.FlushFinish.flush' is done by -- 'swapBuffers' before it returns. Subsequent OpenGL commands can be issued -- immediately after calling 'swapBuffers', but are not executed until the -- buffer exchange is completed. -- -- If the /layer in use/ is not double buffered, 'swapBuffers' has no effect. swapBuffers :: MonadIO m => m () swapBuffers = glutSwapBuffers -------------------------------------------------------------------------------- -- $ChangingTheWindowGeometry -- Note that the requests by 'windowPosition', 'windowSize', and 'fullScreen' -- are not processed immediately. A request is executed after returning to the -- main event loop. This allows multiple requests to the same window to be -- coalesced. -- -- 'windowPosition' and 'windowSize' requests on a window will disable the full -- screen status of the window. -------------------------------------------------------------------------------- -- | Controls the position of the /current window/. For top-level windows, -- parameters of 'Position' are pixel offsets from the screen origin. For -- subwindows, the parameters are pixel offsets from the window\'s parent window -- origin. -- -- In the case of top-level windows, setting 'windowPosition' is considered only -- a request for positioning the window. The window system is free to apply its -- own policies to top-level window placement. The intent is that top-level -- windows should be repositioned according to the value of 'windowPosition'. windowPosition :: StateVar Position windowPosition = makeStateVar getWindowPosition setWindowPosition setWindowPosition :: Position -> IO () setWindowPosition (Position x y) = glutPositionWindow (fromIntegral x) (fromIntegral y) getWindowPosition :: IO Position getWindowPosition = do x <- simpleGet fromIntegral glut_WINDOW_X y <- simpleGet fromIntegral glut_WINDOW_Y return $ Position x y -------------------------------------------------------------------------------- -- | Controls the size of the /current window/. The parameters of 'Size' are -- size extents in pixels. The width and height must be positive values. -- -- In the case of top-level windows, setting 'windowSize' is considered only a -- request for sizing the window. The window system is free to apply its own -- policies to top-level window sizing. The intent is that top-level windows -- should be reshaped according to the value of 'windowSize'. Whether a reshape -- actually takes effect and, if so, the reshaped dimensions are reported to the -- program by a reshape callback. windowSize :: StateVar Size windowSize = makeStateVar getWindowSize setWindowSize setWindowSize :: Size -> IO () setWindowSize (Size w h) = glutReshapeWindow (fromIntegral w) (fromIntegral h) getWindowSize :: IO Size getWindowSize = do w <- simpleGet fromIntegral glut_WINDOW_WIDTH h <- simpleGet fromIntegral glut_WINDOW_HEIGHT return $ Size w h -------------------------------------------------------------------------------- -- | Request that the /current window/ be made full screen. The exact semantics -- of what full screen means may vary by window system. The intent is to make -- the window as large as possible and disable any window decorations or borders -- added the window system. The window width and height are not guaranteed to be -- the same as the screen width and height, but that is the intent of making a -- window full screen. -- -- 'fullScreen' is defined to work only on top-level windows. -- -- /X Implementation Notes:/ In the X implementation of GLUT, full screen is -- implemented by sizing and positioning the window to cover the entire screen -- and posting the @_MOTIF_WM_HINTS@ property on the window requesting -- absolutely no decorations. Non-Motif window managers may not respond to -- @_MOTIF_WM_HINTS@. fullScreen :: MonadIO m => m () fullScreen = glutFullScreen -------------------------------------------------------------------------------- -- | (/freeglut only/) Toggle between windowed and full screen mode. fullScreenToggle :: MonadIO m => m () fullScreenToggle = glutFullScreenToggle -------------------------------------------------------------------------------- -- | (/freeglut only/) If we are in full screen mode, resize the current window -- back to its original size. leaveFullScreen :: MonadIO m => m () leaveFullScreen = glutLeaveFullScreen -------------------------------------------------------------------------------- -- $ManipulatingTheStackingOrder -- 'pushWindow' and 'popWindow' work on both top-level windows and subwindows. -- The effect of pushing and popping windows does not take place immediately. -- Instead the push or pop is saved for execution upon return to the GLUT event -- loop. Subsequent pop or push requests on a window replace the previously -- saved request for that window. The effect of pushing and popping top-level -- windows is subject to the window system\'s policy for restacking windows. -- | Change the stacking order of the /current window/ relative to its siblings -- (lowering it). pushWindow :: MonadIO m => m () pushWindow = glutPushWindow -- | Change the stacking order of the /current window/ relative to its siblings, -- bringing the /current window/ closer to the top. popWindow :: MonadIO m => m () popWindow = glutPopWindow -------------------------------------------------------------------------------- -- | The display status of a window. data WindowStatus = Shown | Hidden | Iconified deriving ( Eq, Ord, Show ) -- | Controls the display status of the /current window/. -- -- Note that the effect of showing, hiding, and iconifying windows does not take -- place immediately. Instead the requests are saved for execution upon return -- to the GLUT event loop. Subsequent show, hide, or iconification requests on a -- window replace the previously saved request for that window. The effect of -- hiding, showing, or iconifying top-level windows is subject to the window -- system\'s policy for displaying windows. Subwindows can\'t be iconified. windowStatus :: SettableStateVar WindowStatus windowStatus = makeSettableStateVar setStatus where setStatus Shown = glutShowWindow setStatus Hidden = glutHideWindow setStatus Iconified = glutIconifyWindow -------------------------------------------------------------------------------- -- $ChangingTheWindowIconTitle -- 'windowTitle' and 'iconTitle' should be set only when the /current -- window/ is a top-level window. Upon creation of a top-level window, the -- window and icon names are determined by the name given to 'createWindow'. -- Once created, setting 'windowTitle' and 'iconTitle' can change the window and -- icon names respectively of top-level windows. Each call requests the window -- system change the title appropriately. Requests are not buffered or -- coalesced. The policy by which the window and icon name are displayed is -- window system dependent. -- | Controls the window title of the /current top-level window/. windowTitle :: SettableStateVar String windowTitle = makeSettableStateVar $ \name -> withCString name glutSetWindowTitle -- | Controls the icon title of the /current top-level window/. iconTitle :: SettableStateVar String iconTitle = makeSettableStateVar $ \name -> withCString name glutSetIconTitle -------------------------------------------------------------------------------- -- | The different cursor images GLUT supports. data Cursor = RightArrow -- ^ Arrow pointing up and to the right. | LeftArrow -- ^ Arrow pointing up and to the left. | Info -- ^ Pointing hand. | Destroy -- ^ Skull & cross bones. | Help -- ^ Question mark. | Cycle -- ^ Arrows rotating in a circle. | Spray -- ^ Spray can. | Wait -- ^ Wrist watch. | Text -- ^ Insertion point cursor for text. | Crosshair -- ^ Simple cross-hair. | UpDown -- ^ Bi-directional pointing up & down. | LeftRight -- ^ Bi-directional pointing left & right. | TopSide -- ^ Arrow pointing to top side. | BottomSide -- ^ Arrow pointing to bottom side. | LeftSide -- ^ Arrow pointing to left side. | RightSide -- ^ Arrow pointing to right side. | TopLeftCorner -- ^ Arrow pointing to top-left corner. | TopRightCorner -- ^ Arrow pointing to top-right corner. | BottomRightCorner -- ^ Arrow pointing to bottom-left corner. | BottomLeftCorner -- ^ Arrow pointing to bottom-right corner. | Inherit -- ^ Use parent\'s cursor. | None -- ^ Invisible cursor. | FullCrosshair -- ^ Full-screen cross-hair cursor (if possible, otherwise 'Crosshair'). deriving ( Eq, Ord, Show ) marshalCursor :: Cursor -> CInt marshalCursor x = case x of RightArrow -> glut_CURSOR_RIGHT_ARROW LeftArrow -> glut_CURSOR_LEFT_ARROW Info -> glut_CURSOR_INFO Destroy -> glut_CURSOR_DESTROY Help -> glut_CURSOR_HELP Cycle -> glut_CURSOR_CYCLE Spray -> glut_CURSOR_SPRAY Wait -> glut_CURSOR_WAIT Text -> glut_CURSOR_TEXT Crosshair -> glut_CURSOR_CROSSHAIR UpDown -> glut_CURSOR_UP_DOWN LeftRight -> glut_CURSOR_LEFT_RIGHT TopSide -> glut_CURSOR_TOP_SIDE BottomSide -> glut_CURSOR_BOTTOM_SIDE LeftSide -> glut_CURSOR_LEFT_SIDE RightSide -> glut_CURSOR_RIGHT_SIDE TopLeftCorner -> glut_CURSOR_TOP_LEFT_CORNER TopRightCorner -> glut_CURSOR_TOP_RIGHT_CORNER BottomRightCorner -> glut_CURSOR_BOTTOM_RIGHT_CORNER BottomLeftCorner -> glut_CURSOR_BOTTOM_LEFT_CORNER Inherit -> glut_CURSOR_INHERIT None -> glut_CURSOR_NONE FullCrosshair -> glut_CURSOR_FULL_CROSSHAIR unmarshalCursor :: CInt -> Cursor unmarshalCursor x | x == glut_CURSOR_RIGHT_ARROW = RightArrow | x == glut_CURSOR_LEFT_ARROW = LeftArrow | x == glut_CURSOR_INFO = Info | x == glut_CURSOR_DESTROY = Destroy | x == glut_CURSOR_HELP = Help | x == glut_CURSOR_CYCLE = Cycle | x == glut_CURSOR_SPRAY = Spray | x == glut_CURSOR_WAIT = Wait | x == glut_CURSOR_TEXT = Text | x == glut_CURSOR_CROSSHAIR = Crosshair | x == glut_CURSOR_UP_DOWN = UpDown | x == glut_CURSOR_LEFT_RIGHT = LeftRight | x == glut_CURSOR_TOP_SIDE = TopSide | x == glut_CURSOR_BOTTOM_SIDE = BottomSide | x == glut_CURSOR_LEFT_SIDE = LeftSide | x == glut_CURSOR_RIGHT_SIDE = RightSide | x == glut_CURSOR_TOP_LEFT_CORNER = TopLeftCorner | x == glut_CURSOR_TOP_RIGHT_CORNER = TopRightCorner | x == glut_CURSOR_BOTTOM_RIGHT_CORNER = BottomRightCorner | x == glut_CURSOR_BOTTOM_LEFT_CORNER = BottomLeftCorner | x == glut_CURSOR_INHERIT = Inherit | x == glut_CURSOR_NONE = None | x == glut_CURSOR_FULL_CROSSHAIR = FullCrosshair | otherwise = error ("unmarshalCursor: illegal value " ++ show x) -------------------------------------------------------------------------------- -- | Change the cursor image of the /current window/. Each call requests the -- window system change the cursor appropriately. The cursor image when a window -- is created is 'Inherit'. The exact cursor images used are implementation -- dependent. The intent is for the image to convey the meaning of the cursor -- name. For a top-level window, 'Inherit' uses the default window system -- cursor. -- -- /X Implementation Notes:/ GLUT for X uses SGI\'s @_SGI_CROSSHAIR_CURSOR@ -- convention to access a full-screen cross-hair cursor if possible. cursor :: StateVar Cursor cursor = makeStateVar getCursor setCursor setCursor :: Cursor -> IO () setCursor = glutSetCursor . marshalCursor getCursor :: IO Cursor getCursor = simpleGet unmarshalCursor glut_WINDOW_CURSOR -------------------------------------------------------------------------------- -- | Setting 'pointerPosition' warps the window system\'s pointer to a new -- location relative to the origin of the /current window/ by the specified -- pixel offset, which may be negative. The warp is done immediately. -- -- If the pointer would be warped outside the screen\'s frame buffer region, the -- location will be clamped to the nearest screen edge. The window system is -- allowed to further constrain the pointer\'s location in window system -- dependent ways. -- -- Good advice from Xlib\'s @XWarpPointer@ man page: \"There is seldom any -- reason for calling this function. The pointer should normally be left to the -- user.\" pointerPosition :: SettableStateVar Position pointerPosition = makeSettableStateVar $ \(Position x y) -> glutWarpPointer (fromIntegral x) (fromIntegral y) GLUT-2.7.0.16/src/Graphics/UI/GLUT/Callbacks/Registration.hs0000644000000000000000000001403013255126367021222 0ustar0000000000000000{-# OPTIONS_GHC -fno-cse #-} {-# OPTIONS_HADDOCK hide #-} -------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Callbacks.Registration -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Callbacks.Registration ( CallbackType(..), registerForCleanup, setCallback, getCurrentWindow ) where -------------------------------------------------------------------------------- import Control.Monad ( when ) import Data.IORef ( IORef, newIORef, readIORef, writeIORef, modifyIORef ) import qualified Data.Map as M import Data.StateVar ( get ) import Foreign.Ptr ( FunPtr, nullFunPtr, freeHaskellFunPtr ) import System.IO.Unsafe ( unsafePerformIO ) import Graphics.UI.GLUT.Raw import Graphics.UI.GLUT.Window -------------------------------------------------------------------------------- -- No timer callback here, because they are one-shot and "self destroy" data CallbackType = DisplayCB | OverlayDisplayCB | ReshapeCB | KeyboardCB | KeyboardUpCB | MouseCB | MotionCB | PassiveMotionCB | CrossingCB | VisibilityCB | WindowStatusCB | SpecialCB | SpecialUpCB | SpaceballMotionCB | SpaceballRotateCB | SpaceballButtonCB | ButtonBoxCB | DialsCB | TabletMotionCB | TabletButtonCB | JoystickCB | MenuStatusCB | IdleCB -- freeglut-only callback types | CloseCB | MouseWheelCB | PositionCB | MultiEntryCB | MultiMotionCB | MultiButtonCB | MultiPassiveCB | InitContextCB | AppStatusCB deriving ( Eq, Ord ) isGlobal :: CallbackType -> Bool isGlobal MenuStatusCB = True isGlobal IdleCB = True isGlobal _ = False -------------------------------------------------------------------------------- -- To uniquely identify a particular callback, the associated window is needed -- for window callbacks. data CallbackID = CallbackID (Maybe Window) CallbackType deriving ( Eq, Ord ) getCallbackID :: CallbackType -> IO CallbackID getCallbackID callbackType = do maybeWindow <- if isGlobal callbackType then return Nothing else fmap Just $ getCurrentWindow "getCallbackID" return $ CallbackID maybeWindow callbackType getCurrentWindow :: String -> IO Window getCurrentWindow func = do win <- get currentWindow maybe (error (func ++ ": no current window")) return win -------------------------------------------------------------------------------- -- This seems to be a common Haskell hack nowadays: A plain old global variable -- with an associated mutator. Perhaps some language/library support is needed? {-# NOINLINE theCallbackTable #-} theCallbackTable :: IORef (CallbackTable a) theCallbackTable = unsafePerformIO (newIORef emptyCallbackTable) getCallbackTable :: IO (CallbackTable a) getCallbackTable = readIORef theCallbackTable modifyCallbackTable :: (CallbackTable a -> CallbackTable a) -> IO () modifyCallbackTable = modifyIORef theCallbackTable -------------------------------------------------------------------------------- type CallbackTable a = M.Map CallbackID (FunPtr a) emptyCallbackTable :: CallbackTable a emptyCallbackTable = M.empty lookupInCallbackTable :: CallbackID -> IO (Maybe (FunPtr a)) lookupInCallbackTable callbackID = fmap (M.lookup callbackID) getCallbackTable deleteFromCallbackTable :: CallbackID -> IO () deleteFromCallbackTable callbackID = modifyCallbackTable (M.delete callbackID) addToCallbackTable :: CallbackID -> FunPtr a -> IO () addToCallbackTable callbackID funPtr = modifyCallbackTable (M.insert callbackID funPtr) -------------------------------------------------------------------------------- -- Another global mutable variable: The list of function pointers ready to be -- freed by freeHaskellFunPtr {-# NOINLINE theCleanupList #-} theCleanupList :: IORef [FunPtr a] theCleanupList = unsafePerformIO (newIORef []) getCleanupList :: IO [FunPtr a] getCleanupList = readIORef theCleanupList setCleanupList :: [FunPtr a] -> IO () setCleanupList = writeIORef theCleanupList -------------------------------------------------------------------------------- -- And yet another mutable (write-once) variable: A function pointer to a -- callback which frees all function pointers on the cleanup list. {-# NOINLINE theScavenger #-} theScavenger :: IORef (FunPtr TimerFunc) theScavenger = unsafePerformIO (newIORef =<< makeTimerFunc (\_ -> do cleanupList <- getCleanupList mapM_ freeHaskellFunPtr cleanupList setCleanupList [])) getScavenger :: IO (FunPtr TimerFunc) getScavenger = readIORef theScavenger -------------------------------------------------------------------------------- -- Here is the really cunning stuff: If an element is added to the cleanup list -- when it is empty, register an immediate callback at GLUT to free the list as -- soon as possible. registerForCleanup :: FunPtr a -> IO () registerForCleanup funPtr = do oldCleanupList <- getCleanupList setCleanupList (funPtr : oldCleanupList) when (null oldCleanupList) $ do scavenger <- getScavenger glutTimerFunc 0 scavenger 0 -------------------------------------------------------------------------------- setCallback :: CallbackType -> (FunPtr a -> IO ()) -> (b -> IO (FunPtr a)) -> Maybe b -> IO () setCallback callbackType registerAtGLUT makeCallback maybeCallback = do callbackID <- getCallbackID callbackType maybeOldFunPtr <- lookupInCallbackTable callbackID case maybeOldFunPtr of Nothing -> return () Just oldFunPtr -> do registerForCleanup oldFunPtr deleteFromCallbackTable callbackID case maybeCallback of Nothing -> registerAtGLUT nullFunPtr Just callback -> do newFunPtr <- makeCallback callback addToCallbackTable callbackID newFunPtr registerAtGLUT newFunPtr GLUT-2.7.0.16/src/Graphics/UI/GLUT/QueryUtils.hs0000644000000000000000000000207113255126367017021 0ustar0000000000000000{-# OPTIONS_HADDOCK hide #-} -------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.QueryUtils -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- This is a purely internal module with utilities to query GLUT state. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.QueryUtils ( Getter, simpleGet, layerGet, deviceGet ) where import Foreign.C.Types ( CInt ) import Graphics.Rendering.OpenGL ( GLenum ) import Graphics.UI.GLUT.Raw -------------------------------------------------------------------------------- type PrimGetter = GLenum -> IO CInt type Getter a = (CInt -> a) -> GLenum -> IO a makeGetter :: PrimGetter -> Getter a makeGetter g f = fmap f . g simpleGet, layerGet, deviceGet :: Getter a simpleGet = makeGetter glutGet layerGet = makeGetter glutLayerGet deviceGet = makeGetter glutDeviceGet GLUT-2.7.0.16/src/Graphics/UI/GLUT/Raw.hs0000644000000000000000000000144413255126367015427 0ustar0000000000000000{-# OPTIONS_HADDOCK hide #-} ----------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Raw -- Copyright : (c) Sven Panne 2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- A convenience module, combining all raw GLUT modules. -- ----------------------------------------------------------------------------- module Graphics.UI.GLUT.Raw ( module Graphics.UI.GLUT.Raw.Callbacks, module Graphics.UI.GLUT.Raw.Fonts, module Graphics.UI.GLUT.Raw.Functions, module Graphics.UI.GLUT.Raw.Tokens ) where import Graphics.UI.GLUT.Raw.Callbacks import Graphics.UI.GLUT.Raw.Fonts import Graphics.UI.GLUT.Raw.Functions import Graphics.UI.GLUT.Raw.Tokens GLUT-2.7.0.16/src/Graphics/UI/GLUT/Raw/Callbacks.hs0000644000000000000000000001607713255126367017316 0ustar0000000000000000{-# OPTIONS_HADDOCK hide #-} ----------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Raw.Callbacks -- Copyright : (c) Sven Panne 2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- All GLUT callbacks. -- ----------------------------------------------------------------------------- module Graphics.UI.GLUT.Raw.Callbacks ( AppStatusFunc, makeAppStatusFunc, ButtonBoxFunc, makeButtonBoxFunc, CloseFunc, makeCloseFunc, DialsFunc, makeDialsFunc, DisplayFunc, makeDisplayFunc, EntryFunc, makeEntryFunc, IdleFunc, makeIdleFunc, InitContextFunc, makeInitContextFunc, JoystickFunc, makeJoystickFunc, KeyboardFunc, makeKeyboardFunc, KeyboardUpFunc, makeKeyboardUpFunc, MenuDestroyFunc, makeMenuDestroyFunc, MenuFunc, makeMenuFunc, MenuStateFunc, makeMenuStateFunc, MenuStatusFunc, makeMenuStatusFunc, MotionFunc, makeMotionFunc, MouseFunc, makeMouseFunc, MouseWheelFunc, makeMouseWheelFunc, MultiButtonFunc, makeMultiButtonFunc, MultiEntryFunc, makeMultiEntryFunc, MultiMotionFunc, makeMultiMotionFunc, MultiPassiveFunc, makeMultiPassiveFunc, OverlayDisplayFunc, makeOverlayDisplayFunc, PassiveMotionFunc, makePassiveMotionFunc, PositionFunc, makePositionFunc, ReshapeFunc, makeReshapeFunc, SpaceballButtonFunc, makeSpaceballButtonFunc, SpaceballMotionFunc, makeSpaceballMotionFunc, SpaceballRotateFunc, makeSpaceballRotateFunc, SpecialFunc, makeSpecialFunc, SpecialUpFunc, makeSpecialUpFunc, TabletButtonFunc, makeTabletButtonFunc, TabletMotionFunc, makeTabletMotionFunc, TimerFunc, makeTimerFunc, VisibilityFunc, makeVisibilityFunc, WMCloseFunc, makeWMCloseFunc, WindowStatusFunc, makeWindowStatusFunc ) where import Foreign.C.Types import Foreign.Ptr type AppStatusFunc = CInt -> IO () foreign import ccall "wrapper" makeAppStatusFunc :: AppStatusFunc -> IO (FunPtr AppStatusFunc) type ButtonBoxFunc = CInt -> CInt -> IO () foreign import ccall "wrapper" makeButtonBoxFunc :: ButtonBoxFunc -> IO (FunPtr ButtonBoxFunc) type CloseFunc = IO () foreign import ccall "wrapper" makeCloseFunc :: CloseFunc -> IO (FunPtr CloseFunc) type DialsFunc = CInt -> CInt -> IO () foreign import ccall "wrapper" makeDialsFunc :: DialsFunc -> IO (FunPtr DialsFunc) type DisplayFunc = IO () foreign import ccall "wrapper" makeDisplayFunc :: DisplayFunc -> IO (FunPtr DisplayFunc) type EntryFunc = CInt -> IO () foreign import ccall "wrapper" makeEntryFunc :: EntryFunc -> IO (FunPtr EntryFunc) type IdleFunc = IO () foreign import ccall "wrapper" makeIdleFunc :: IdleFunc -> IO (FunPtr IdleFunc) type InitContextFunc = IO () foreign import ccall "wrapper" makeInitContextFunc :: InitContextFunc -> IO (FunPtr InitContextFunc) type JoystickFunc = CUInt -> CInt -> CInt -> CInt -> IO () foreign import ccall "wrapper" makeJoystickFunc :: JoystickFunc -> IO (FunPtr JoystickFunc) type KeyboardFunc = CUChar -> CInt -> CInt -> IO () foreign import ccall "wrapper" makeKeyboardFunc :: KeyboardFunc -> IO (FunPtr KeyboardFunc) type KeyboardUpFunc = CUChar -> CInt -> CInt -> IO () foreign import ccall "wrapper" makeKeyboardUpFunc :: KeyboardUpFunc -> IO (FunPtr KeyboardUpFunc) type MenuDestroyFunc = IO () foreign import ccall "wrapper" makeMenuDestroyFunc :: MenuDestroyFunc -> IO (FunPtr MenuDestroyFunc) type MenuFunc = CInt -> IO () foreign import ccall "wrapper" makeMenuFunc :: MenuFunc -> IO (FunPtr MenuFunc) type MenuStateFunc = CInt -> IO () foreign import ccall "wrapper" makeMenuStateFunc :: MenuStateFunc -> IO (FunPtr MenuStateFunc) type MenuStatusFunc = CInt -> CInt -> CInt -> IO () foreign import ccall "wrapper" makeMenuStatusFunc :: MenuStatusFunc -> IO (FunPtr MenuStatusFunc) type MotionFunc = CInt -> CInt -> IO () foreign import ccall "wrapper" makeMotionFunc :: MotionFunc -> IO (FunPtr MotionFunc) type MouseFunc = CInt -> CInt -> CInt -> CInt -> IO () foreign import ccall "wrapper" makeMouseFunc :: MouseFunc -> IO (FunPtr MouseFunc) type MouseWheelFunc = CInt -> CInt -> CInt -> CInt -> IO () foreign import ccall "wrapper" makeMouseWheelFunc :: MouseWheelFunc -> IO (FunPtr MouseWheelFunc) type MultiButtonFunc = CInt -> CInt -> CInt -> CInt -> CInt -> IO () foreign import ccall "wrapper" makeMultiButtonFunc :: MultiButtonFunc -> IO (FunPtr MultiButtonFunc) type MultiEntryFunc = CInt -> CInt -> IO () foreign import ccall "wrapper" makeMultiEntryFunc :: MultiEntryFunc -> IO (FunPtr MultiEntryFunc) type MultiMotionFunc = CInt -> CInt -> CInt -> IO () foreign import ccall "wrapper" makeMultiMotionFunc :: MultiMotionFunc -> IO (FunPtr MultiMotionFunc) type MultiPassiveFunc = CInt -> CInt -> CInt -> IO () foreign import ccall "wrapper" makeMultiPassiveFunc :: MultiPassiveFunc -> IO (FunPtr MultiPassiveFunc) type OverlayDisplayFunc = IO () foreign import ccall "wrapper" makeOverlayDisplayFunc :: OverlayDisplayFunc -> IO (FunPtr OverlayDisplayFunc) type PassiveMotionFunc = CInt -> CInt -> IO () foreign import ccall "wrapper" makePassiveMotionFunc :: PassiveMotionFunc -> IO (FunPtr PassiveMotionFunc) type PositionFunc = CInt -> CInt -> IO () foreign import ccall "wrapper" makePositionFunc :: PositionFunc -> IO (FunPtr PositionFunc) type ReshapeFunc = CInt -> CInt -> IO () foreign import ccall "wrapper" makeReshapeFunc :: ReshapeFunc -> IO (FunPtr ReshapeFunc) type SpaceballButtonFunc = CInt -> CInt -> IO () foreign import ccall "wrapper" makeSpaceballButtonFunc :: SpaceballButtonFunc -> IO (FunPtr SpaceballButtonFunc) type SpaceballMotionFunc = CInt -> CInt -> CInt -> IO () foreign import ccall "wrapper" makeSpaceballMotionFunc :: SpaceballMotionFunc -> IO (FunPtr SpaceballMotionFunc) type SpaceballRotateFunc = CInt -> CInt -> CInt -> IO () foreign import ccall "wrapper" makeSpaceballRotateFunc :: SpaceballRotateFunc -> IO (FunPtr SpaceballRotateFunc) type SpecialFunc = CInt -> CInt -> CInt -> IO () foreign import ccall "wrapper" makeSpecialFunc :: SpecialFunc -> IO (FunPtr SpecialFunc) type SpecialUpFunc = CInt -> CInt -> CInt -> IO () foreign import ccall "wrapper" makeSpecialUpFunc :: SpecialUpFunc -> IO (FunPtr SpecialUpFunc) type TabletButtonFunc = CInt -> CInt -> CInt -> CInt -> IO () foreign import ccall "wrapper" makeTabletButtonFunc :: TabletButtonFunc -> IO (FunPtr TabletButtonFunc) type TabletMotionFunc = CInt -> CInt -> IO () foreign import ccall "wrapper" makeTabletMotionFunc :: TabletMotionFunc -> IO (FunPtr TabletMotionFunc) type TimerFunc = CInt -> IO () foreign import ccall "wrapper" makeTimerFunc :: TimerFunc -> IO (FunPtr TimerFunc) type VisibilityFunc = CInt -> IO () foreign import ccall "wrapper" makeVisibilityFunc :: VisibilityFunc -> IO (FunPtr VisibilityFunc) type WMCloseFunc = IO () foreign import ccall "wrapper" makeWMCloseFunc :: WMCloseFunc -> IO (FunPtr WMCloseFunc) type WindowStatusFunc = CInt -> IO () foreign import ccall "wrapper" makeWindowStatusFunc :: WindowStatusFunc -> IO (FunPtr WindowStatusFunc) GLUT-2.7.0.16/src/Graphics/UI/GLUT/Raw/Fonts.hs0000644000000000000000000001031713255126367016517 0ustar0000000000000000{-# OPTIONS_HADDOCK hide #-} ----------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Raw.Fonts -- Copyright : (c) Sven Panne 2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- Our own functions to access font identifiers in a portable way. -- ----------------------------------------------------------------------------- module Graphics.UI.GLUT.Raw.Fonts ( BitmapFont(..), GLUTbitmapFont, marshalBitmapFont, StrokeFont(..), GLUTstrokeFont, marshalStrokeFont ) where import Control.Monad.IO.Class ( MonadIO(..) ) import Foreign.C.Types import Foreign.Ptr ( Ptr ) -------------------------------------------------------------------------------- -- | The bitmap fonts available in GLUT. The exact bitmap to be used is -- defined by the standard X glyph bitmaps for the X font with the given name. data BitmapFont = Fixed8By13 -- ^ A fixed width font with every character fitting in an 8 -- by 13 pixel rectangle. -- (@-misc-fixed-medium-r-normal--13-120-75-75-C-80-iso8859-1@) | Fixed9By15 -- ^ A fixed width font with every character fitting in an 9 -- by 15 pixel rectangle. -- (@-misc-fixed-medium-r-normal--15-140-75-75-C-90-iso8859-1@) | TimesRoman10 -- ^ A 10-point proportional spaced Times Roman font. -- (@-adobe-times-medium-r-normal--10-100-75-75-p-54-iso8859-1@) | TimesRoman24 -- ^ A 24-point proportional spaced Times Roman font. -- (@-adobe-times-medium-r-normal--24-240-75-75-p-124-iso8859-1@) | Helvetica10 -- ^ A 10-point proportional spaced Helvetica font. -- (@-adobe-helvetica-medium-r-normal--10-100-75-75-p-56-iso8859-1@) | Helvetica12 -- ^ A 12-point proportional spaced Helvetica font. -- (@-adobe-helvetica-medium-r-normal--12-120-75-75-p-67-iso8859-1@) | Helvetica18 -- ^ A 18-point proportional spaced Helvetica font. -- (@-adobe-helvetica-medium-r-normal--18-180-75-75-p-98-iso8859-1@) deriving ( Eq, Ord, Show ) -- Alas, fonts in GLUT are not denoted by some integral value, but by opaque -- pointers on the C side. Even worse: For WinDoze, they are simply small ints, -- casted to void*, for other platforms addresses of global variables are used. -- And all is done via ugly #ifdef-ed #defines... Aaaaargl! So the only portable -- way is using integers on the Haskell side and doing the marshaling via some -- small C wrappers around those macros. *sigh* type GLUTbitmapFont = Ptr () marshalBitmapFont :: MonadIO m => BitmapFont -> m GLUTbitmapFont marshalBitmapFont x = liftIO $ case x of Fixed8By13 -> hs_GLUT_marshalBitmapFont 0 Fixed9By15 -> hs_GLUT_marshalBitmapFont 1 TimesRoman10 -> hs_GLUT_marshalBitmapFont 2 TimesRoman24 -> hs_GLUT_marshalBitmapFont 3 Helvetica10 -> hs_GLUT_marshalBitmapFont 4 Helvetica12 -> hs_GLUT_marshalBitmapFont 5 Helvetica18 -> hs_GLUT_marshalBitmapFont 6 foreign import ccall unsafe "hs_GLUT_marshalBitmapFont" hs_GLUT_marshalBitmapFont :: CInt -> IO (Ptr a) -------------------------------------------------------------------------------- -- | The stroke fonts available in GLUT. data StrokeFont = Roman -- ^ A proportionally spaced Roman Simplex font for ASCII -- characters 32 through 127. The maximum top character in the -- font is 119.05 units; the bottom descends 33.33 units. | MonoRoman -- ^ A mono-spaced spaced Roman Simplex font (same characters as -- 'Roman') for ASCII characters 32 through 127. The maximum -- top character in the font is 119.05 units; the bottom -- descends 33.33 units. Each character is 104.76 units wide. deriving ( Eq, Ord, Show ) -- Same remarks as for GLUTbitmapFont type GLUTstrokeFont = Ptr () marshalStrokeFont :: MonadIO m => StrokeFont -> m GLUTstrokeFont marshalStrokeFont x = liftIO $ case x of Roman -> hs_GLUT_marshalStrokeFont 0 MonoRoman -> hs_GLUT_marshalStrokeFont 1 foreign import ccall unsafe "hs_GLUT_marshalStrokeFont" hs_GLUT_marshalStrokeFont :: CInt -> IO (Ptr a) GLUT-2.7.0.16/src/Graphics/UI/GLUT/Raw/Functions.hs0000644000000000000000000024177213255126367017411 0ustar0000000000000000{-# LANGUAGE CPP #-} {-# OPTIONS_HADDOCK hide #-} -------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Raw.Functions -- Copyright : (c) Sven Panne 2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- All raw functions from GLUT and freeglut. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Raw.Functions ( isKnown, glutAddMenuEntry, glutAddSubMenu, glutAppStatusFunc, glutAttachMenu, glutBitmapCharacter, glutBitmapHeight, glutBitmapLength, glutBitmapString, glutBitmapWidth, glutButtonBoxFunc, glutChangeToMenuEntry, glutChangeToSubMenu, glutCloseFunc, glutCopyColormap, glutCreateMenu, glutCreateSubWindow, glutCreateWindow, glutDestroyMenu, glutDestroyWindow, glutDetachMenu, glutDeviceGet, glutDialsFunc, glutDisplayFunc, glutEnterGameMode, glutEntryFunc, glutEstablishOverlay, glutExit, glutExtensionSupported, glutForceJoystickFunc, glutFullScreen, glutFullScreenToggle, glutGameModeGet, glutGameModeString, glutGet, glutGetColor, glutGetMenu, glutGetMenuData, glutGetModeValues, glutGetModifiers, glutGetProcAddress, glutGetWindow, glutGetWindowData, glutHideOverlay, glutHideWindow, glutIconifyWindow, glutIdleFunc, glutIgnoreKeyRepeat, glutInit, glutInitContextFlags, glutInitContextFunc, glutInitContextProfile, glutInitContextVersion, glutInitDisplayMode, glutInitDisplayString, glutInitWindowPosition, glutInitWindowSize, glutJoystickFunc, glutKeyboardFunc, glutKeyboardUpFunc, glutLayerGet, glutLeaveFullScreen, glutLeaveGameMode, glutLeaveMainLoop, glutMainLoop, glutMainLoopEvent, glutMenuDestroyFunc, glutMenuStateFunc, glutMenuStatusFunc, glutMotionFunc, glutMouseFunc, glutMouseWheelFunc, glutMultiButtonFunc, glutMultiEntryFunc, glutMultiMotionFunc, glutMultiPassiveFunc, glutOverlayDisplayFunc, glutPassiveMotionFunc, glutPopWindow, glutPositionFunc, glutPositionWindow, glutPostOverlayRedisplay, glutPostRedisplay, glutPostWindowOverlayRedisplay, glutPostWindowRedisplay, glutPushWindow, glutRemoveMenuItem, glutRemoveOverlay, glutReportErrors, glutReshapeFunc, glutReshapeWindow, glutSetColor, glutSetCursor, glutSetIconTitle, glutSetKeyRepeat, glutSetMenu, glutSetMenuData, glutSetMenuFont, glutSetOption, glutSetVertexAttribCoord3, glutSetVertexAttribNormal, glutSetVertexAttribTexCoord2, glutSetWindow, glutSetWindowData, glutSetWindowTitle, glutSetupVideoResizing, glutShowOverlay, glutShowWindow, glutSolidCone, glutSolidCube, glutSolidCylinder, glutSolidDodecahedron, glutSolidIcosahedron, glutSolidOctahedron, glutSolidRhombicDodecahedron, glutSolidSierpinskiSponge, glutSolidSphere, glutSolidTeacup, glutSolidTeapot, glutSolidTeaspoon, glutSolidTetrahedron, glutSolidTorus, glutSpaceballButtonFunc, glutSpaceballMotionFunc, glutSpaceballRotateFunc, glutSpecialFunc, glutSpecialUpFunc, glutStopVideoResizing, glutStrokeCharacter, glutStrokeHeight, glutStrokeLength, glutStrokeString, glutStrokeWidth, glutSwapBuffers, glutTabletButtonFunc, glutTabletMotionFunc, glutTimerFunc, glutUseLayer, glutVideoPan, glutVideoResize, glutVideoResizeGet, glutVisibilityFunc, glutWMCloseFunc, glutWarpPointer, glutWindowStatusFunc, glutWireCone, glutWireCube, glutWireCylinder, glutWireDodecahedron, glutWireIcosahedron, glutWireOctahedron, glutWireRhombicDodecahedron, glutWireSierpinskiSponge, glutWireSphere, glutWireTeacup, glutWireTeapot, glutWireTeaspoon, glutWireTetrahedron, glutWireTorus ) where -- Make the foreign imports happy. import Foreign.C.Types import Control.Monad.IO.Class ( MonadIO(..) ) import Foreign.C.String ( withCString, CString ) import Foreign.Marshal.Error ( throwIf ) import Foreign.Ptr ( Ptr, FunPtr, nullFunPtr ) import Graphics.Rendering.OpenGL ( GLdouble, GLenum, GLfloat, GLint ) import System.IO.Unsafe ( unsafePerformIO ) import Graphics.UI.GLUT.Raw.Callbacks -------------------------------------------------------------------------------- -- | Retrieve a GLUT API entry by name. Throws a userError when no entry with -- the given name was found. getAPIEntry :: String -> IO (FunPtr a) getAPIEntry extensionEntry = throwIfNullFunPtr ("unknown GLUT entry " ++ extensionEntry) $ getAPIEntryInternal extensionEntry throwIfNullFunPtr :: String -> IO (FunPtr a) -> IO (FunPtr a) throwIfNullFunPtr = throwIf (== nullFunPtr) . const getAPIEntryInternal :: String -> IO (FunPtr a) getAPIEntryInternal extensionEntry = withCString extensionEntry hs_GLUT_getProcAddress isKnown :: MonadIO m => String -> m Bool isKnown = liftIO . fmap (/= nullFunPtr) . getAPIEntryInternal foreign import ccall unsafe "hs_GLUT_getProcAddress" hs_GLUT_getProcAddress :: CString -> IO (FunPtr a) -- glutAddMenuEntry ------------------------------------------------------------ glutAddMenuEntry :: MonadIO m => Ptr CChar -> CInt -> m () glutAddMenuEntry v1 v2 = liftIO $ dyn_glutAddMenuEntry ptr_glutAddMenuEntry v1 v2 foreign import CALLCONV "dynamic" dyn_glutAddMenuEntry :: FunPtr (Ptr CChar -> CInt -> IO ()) -> Ptr CChar -> CInt -> IO () {-# NOINLINE ptr_glutAddMenuEntry #-} ptr_glutAddMenuEntry :: FunPtr a ptr_glutAddMenuEntry = unsafePerformIO $ getAPIEntry "glutAddMenuEntry" -- glutAddSubMenu -------------------------------------------------------------- glutAddSubMenu :: MonadIO m => Ptr CChar -> CInt -> m () glutAddSubMenu v1 v2 = liftIO $ dyn_glutAddSubMenu ptr_glutAddSubMenu v1 v2 foreign import CALLCONV "dynamic" dyn_glutAddSubMenu :: FunPtr (Ptr CChar -> CInt -> IO ()) -> Ptr CChar -> CInt -> IO () {-# NOINLINE ptr_glutAddSubMenu #-} ptr_glutAddSubMenu :: FunPtr a ptr_glutAddSubMenu = unsafePerformIO $ getAPIEntry "glutAddSubMenu" -- glutAppStatusFunc ----------------------------------------------------------- glutAppStatusFunc :: MonadIO m => FunPtr AppStatusFunc -> m () glutAppStatusFunc v1 = liftIO $ dyn_glutAppStatusFunc ptr_glutAppStatusFunc v1 foreign import CALLCONV "dynamic" dyn_glutAppStatusFunc :: FunPtr (FunPtr AppStatusFunc -> IO ()) -> FunPtr AppStatusFunc -> IO () {-# NOINLINE ptr_glutAppStatusFunc #-} ptr_glutAppStatusFunc :: FunPtr a ptr_glutAppStatusFunc = unsafePerformIO $ getAPIEntry "glutAppStatusFunc" -- glutAttachMenu -------------------------------------------------------------- glutAttachMenu :: MonadIO m => CInt -> m () glutAttachMenu v1 = liftIO $ dyn_glutAttachMenu ptr_glutAttachMenu v1 foreign import CALLCONV "dynamic" dyn_glutAttachMenu :: FunPtr (CInt -> IO ()) -> CInt -> IO () {-# NOINLINE ptr_glutAttachMenu #-} ptr_glutAttachMenu :: FunPtr a ptr_glutAttachMenu = unsafePerformIO $ getAPIEntry "glutAttachMenu" -- glutBitmapCharacter --------------------------------------------------------- glutBitmapCharacter :: MonadIO m => Ptr a -> CInt -> m () glutBitmapCharacter v1 v2 = liftIO $ dyn_glutBitmapCharacter ptr_glutBitmapCharacter v1 v2 foreign import CALLCONV "dynamic" dyn_glutBitmapCharacter :: FunPtr (Ptr a -> CInt -> IO ()) -> Ptr a -> CInt -> IO () {-# NOINLINE ptr_glutBitmapCharacter #-} ptr_glutBitmapCharacter :: FunPtr a ptr_glutBitmapCharacter = unsafePerformIO $ getAPIEntry "glutBitmapCharacter" -- glutBitmapHeight ------------------------------------------------------------ glutBitmapHeight :: MonadIO m => Ptr a -> m CInt glutBitmapHeight v1 = liftIO $ dyn_glutBitmapHeight ptr_glutBitmapHeight v1 foreign import CALLCONV "dynamic" dyn_glutBitmapHeight :: FunPtr (Ptr a -> IO CInt) -> Ptr a -> IO CInt {-# NOINLINE ptr_glutBitmapHeight #-} ptr_glutBitmapHeight :: FunPtr a ptr_glutBitmapHeight = unsafePerformIO $ getAPIEntry "glutBitmapHeight" -- glutBitmapLength ------------------------------------------------------------ glutBitmapLength :: MonadIO m => Ptr a -> Ptr CUChar -> m CInt glutBitmapLength v1 v2 = liftIO $ dyn_glutBitmapLength ptr_glutBitmapLength v1 v2 foreign import CALLCONV "dynamic" dyn_glutBitmapLength :: FunPtr (Ptr a -> Ptr CUChar -> IO CInt) -> Ptr a -> Ptr CUChar -> IO CInt {-# NOINLINE ptr_glutBitmapLength #-} ptr_glutBitmapLength :: FunPtr a ptr_glutBitmapLength = unsafePerformIO $ getAPIEntry "glutBitmapLength" -- glutBitmapString ------------------------------------------------------------ glutBitmapString :: MonadIO m => Ptr a -> Ptr CUChar -> m () glutBitmapString v1 v2 = liftIO $ dyn_glutBitmapString ptr_glutBitmapString v1 v2 foreign import CALLCONV "dynamic" dyn_glutBitmapString :: FunPtr (Ptr a -> Ptr CUChar -> IO ()) -> Ptr a -> Ptr CUChar -> IO () {-# NOINLINE ptr_glutBitmapString #-} ptr_glutBitmapString :: FunPtr a ptr_glutBitmapString = unsafePerformIO $ getAPIEntry "glutBitmapString" -- glutBitmapWidth ------------------------------------------------------------- glutBitmapWidth :: MonadIO m => Ptr a -> CInt -> m CInt glutBitmapWidth v1 v2 = liftIO $ dyn_glutBitmapWidth ptr_glutBitmapWidth v1 v2 foreign import CALLCONV "dynamic" dyn_glutBitmapWidth :: FunPtr (Ptr a -> CInt -> IO CInt) -> Ptr a -> CInt -> IO CInt {-# NOINLINE ptr_glutBitmapWidth #-} ptr_glutBitmapWidth :: FunPtr a ptr_glutBitmapWidth = unsafePerformIO $ getAPIEntry "glutBitmapWidth" -- glutButtonBoxFunc ----------------------------------------------------------- glutButtonBoxFunc :: MonadIO m => FunPtr ButtonBoxFunc -> m () glutButtonBoxFunc v1 = liftIO $ dyn_glutButtonBoxFunc ptr_glutButtonBoxFunc v1 foreign import CALLCONV "dynamic" dyn_glutButtonBoxFunc :: FunPtr (FunPtr ButtonBoxFunc -> IO ()) -> FunPtr ButtonBoxFunc -> IO () {-# NOINLINE ptr_glutButtonBoxFunc #-} ptr_glutButtonBoxFunc :: FunPtr a ptr_glutButtonBoxFunc = unsafePerformIO $ getAPIEntry "glutButtonBoxFunc" -- glutChangeToMenuEntry ------------------------------------------------------- glutChangeToMenuEntry :: MonadIO m => CInt -> Ptr CChar -> CInt -> m () glutChangeToMenuEntry v1 v2 v3 = liftIO $ dyn_glutChangeToMenuEntry ptr_glutChangeToMenuEntry v1 v2 v3 foreign import CALLCONV "dynamic" dyn_glutChangeToMenuEntry :: FunPtr (CInt -> Ptr CChar -> CInt -> IO ()) -> CInt -> Ptr CChar -> CInt -> IO () {-# NOINLINE ptr_glutChangeToMenuEntry #-} ptr_glutChangeToMenuEntry :: FunPtr a ptr_glutChangeToMenuEntry = unsafePerformIO $ getAPIEntry "glutChangeToMenuEntry" -- glutChangeToSubMenu --------------------------------------------------------- glutChangeToSubMenu :: MonadIO m => CInt -> Ptr CChar -> CInt -> m () glutChangeToSubMenu v1 v2 v3 = liftIO $ dyn_glutChangeToSubMenu ptr_glutChangeToSubMenu v1 v2 v3 foreign import CALLCONV "dynamic" dyn_glutChangeToSubMenu :: FunPtr (CInt -> Ptr CChar -> CInt -> IO ()) -> CInt -> Ptr CChar -> CInt -> IO () {-# NOINLINE ptr_glutChangeToSubMenu #-} ptr_glutChangeToSubMenu :: FunPtr a ptr_glutChangeToSubMenu = unsafePerformIO $ getAPIEntry "glutChangeToSubMenu" -- glutCloseFunc --------------------------------------------------------------- glutCloseFunc :: MonadIO m => FunPtr CloseFunc -> m () glutCloseFunc v1 = liftIO $ dyn_glutCloseFunc ptr_glutCloseFunc v1 foreign import CALLCONV "dynamic" dyn_glutCloseFunc :: FunPtr (FunPtr CloseFunc -> IO ()) -> FunPtr CloseFunc -> IO () {-# NOINLINE ptr_glutCloseFunc #-} ptr_glutCloseFunc :: FunPtr a ptr_glutCloseFunc = unsafePerformIO $ getAPIEntry "glutCloseFunc" -- glutCopyColormap ------------------------------------------------------------ glutCopyColormap :: MonadIO m => CInt -> m () glutCopyColormap v1 = liftIO $ dyn_glutCopyColormap ptr_glutCopyColormap v1 foreign import CALLCONV "dynamic" dyn_glutCopyColormap :: FunPtr (CInt -> IO ()) -> CInt -> IO () {-# NOINLINE ptr_glutCopyColormap #-} ptr_glutCopyColormap :: FunPtr a ptr_glutCopyColormap = unsafePerformIO $ getAPIEntry "glutCopyColormap" -- glutCreateMenu -------------------------------------------------------------- glutCreateMenu :: MonadIO m => FunPtr MenuFunc -> m CInt glutCreateMenu v1 = liftIO $ dyn_glutCreateMenu ptr_glutCreateMenu v1 foreign import CALLCONV "dynamic" dyn_glutCreateMenu :: FunPtr (FunPtr MenuFunc -> IO CInt) -> FunPtr MenuFunc -> IO CInt {-# NOINLINE ptr_glutCreateMenu #-} ptr_glutCreateMenu :: FunPtr a ptr_glutCreateMenu = unsafePerformIO $ getAPIEntry "glutCreateMenu" -- glutCreateSubWindow --------------------------------------------------------- glutCreateSubWindow :: MonadIO m => CInt -> CInt -> CInt -> CInt -> CInt -> m CInt glutCreateSubWindow v1 v2 v3 v4 v5 = liftIO $ dyn_glutCreateSubWindow ptr_glutCreateSubWindow v1 v2 v3 v4 v5 foreign import CALLCONV "dynamic" dyn_glutCreateSubWindow :: FunPtr (CInt -> CInt -> CInt -> CInt -> CInt -> IO CInt) -> CInt -> CInt -> CInt -> CInt -> CInt -> IO CInt {-# NOINLINE ptr_glutCreateSubWindow #-} ptr_glutCreateSubWindow :: FunPtr a ptr_glutCreateSubWindow = unsafePerformIO $ getAPIEntry "glutCreateSubWindow" -- glutCreateWindow ------------------------------------------------------------ glutCreateWindow :: MonadIO m => Ptr CChar -> m CInt glutCreateWindow v1 = liftIO $ dyn_glutCreateWindow ptr_glutCreateWindow v1 foreign import CALLCONV "dynamic" dyn_glutCreateWindow :: FunPtr (Ptr CChar -> IO CInt) -> Ptr CChar -> IO CInt {-# NOINLINE ptr_glutCreateWindow #-} ptr_glutCreateWindow :: FunPtr a ptr_glutCreateWindow = unsafePerformIO $ getAPIEntry "glutCreateWindow" -- glutDestroyMenu ------------------------------------------------------------- glutDestroyMenu :: MonadIO m => CInt -> m () glutDestroyMenu v1 = liftIO $ dyn_glutDestroyMenu ptr_glutDestroyMenu v1 foreign import CALLCONV "dynamic" dyn_glutDestroyMenu :: FunPtr (CInt -> IO ()) -> CInt -> IO () {-# NOINLINE ptr_glutDestroyMenu #-} ptr_glutDestroyMenu :: FunPtr a ptr_glutDestroyMenu = unsafePerformIO $ getAPIEntry "glutDestroyMenu" -- glutDestroyWindow ----------------------------------------------------------- glutDestroyWindow :: MonadIO m => CInt -> m () glutDestroyWindow v1 = liftIO $ dyn_glutDestroyWindow ptr_glutDestroyWindow v1 foreign import CALLCONV "dynamic" dyn_glutDestroyWindow :: FunPtr (CInt -> IO ()) -> CInt -> IO () {-# NOINLINE ptr_glutDestroyWindow #-} ptr_glutDestroyWindow :: FunPtr a ptr_glutDestroyWindow = unsafePerformIO $ getAPIEntry "glutDestroyWindow" -- glutDetachMenu -------------------------------------------------------------- glutDetachMenu :: MonadIO m => CInt -> m () glutDetachMenu v1 = liftIO $ dyn_glutDetachMenu ptr_glutDetachMenu v1 foreign import CALLCONV "dynamic" dyn_glutDetachMenu :: FunPtr (CInt -> IO ()) -> CInt -> IO () {-# NOINLINE ptr_glutDetachMenu #-} ptr_glutDetachMenu :: FunPtr a ptr_glutDetachMenu = unsafePerformIO $ getAPIEntry "glutDetachMenu" -- glutDeviceGet --------------------------------------------------------------- glutDeviceGet :: MonadIO m => GLenum -> m CInt glutDeviceGet v1 = liftIO $ dyn_glutDeviceGet ptr_glutDeviceGet v1 foreign import CALLCONV "dynamic" dyn_glutDeviceGet :: FunPtr (GLenum -> IO CInt) -> GLenum -> IO CInt {-# NOINLINE ptr_glutDeviceGet #-} ptr_glutDeviceGet :: FunPtr a ptr_glutDeviceGet = unsafePerformIO $ getAPIEntry "glutDeviceGet" -- glutDialsFunc --------------------------------------------------------------- glutDialsFunc :: MonadIO m => FunPtr DialsFunc -> m () glutDialsFunc v1 = liftIO $ dyn_glutDialsFunc ptr_glutDialsFunc v1 foreign import CALLCONV "dynamic" dyn_glutDialsFunc :: FunPtr (FunPtr DialsFunc -> IO ()) -> FunPtr DialsFunc -> IO () {-# NOINLINE ptr_glutDialsFunc #-} ptr_glutDialsFunc :: FunPtr a ptr_glutDialsFunc = unsafePerformIO $ getAPIEntry "glutDialsFunc" -- glutDisplayFunc ------------------------------------------------------------- glutDisplayFunc :: MonadIO m => FunPtr DisplayFunc -> m () glutDisplayFunc v1 = liftIO $ dyn_glutDisplayFunc ptr_glutDisplayFunc v1 foreign import CALLCONV "dynamic" dyn_glutDisplayFunc :: FunPtr (FunPtr DisplayFunc -> IO ()) -> FunPtr DisplayFunc -> IO () {-# NOINLINE ptr_glutDisplayFunc #-} ptr_glutDisplayFunc :: FunPtr a ptr_glutDisplayFunc = unsafePerformIO $ getAPIEntry "glutDisplayFunc" -- glutEnterGameMode ----------------------------------------------------------- glutEnterGameMode :: MonadIO m => m CInt glutEnterGameMode = liftIO $ dyn_glutEnterGameMode ptr_glutEnterGameMode foreign import CALLCONV "dynamic" dyn_glutEnterGameMode :: FunPtr (IO CInt) -> IO CInt {-# NOINLINE ptr_glutEnterGameMode #-} ptr_glutEnterGameMode :: FunPtr a ptr_glutEnterGameMode = unsafePerformIO $ getAPIEntry "glutEnterGameMode" -- glutEntryFunc --------------------------------------------------------------- glutEntryFunc :: MonadIO m => FunPtr EntryFunc -> m () glutEntryFunc v1 = liftIO $ dyn_glutEntryFunc ptr_glutEntryFunc v1 foreign import CALLCONV "dynamic" dyn_glutEntryFunc :: FunPtr (FunPtr EntryFunc -> IO ()) -> FunPtr EntryFunc -> IO () {-# NOINLINE ptr_glutEntryFunc #-} ptr_glutEntryFunc :: FunPtr a ptr_glutEntryFunc = unsafePerformIO $ getAPIEntry "glutEntryFunc" -- glutEstablishOverlay -------------------------------------------------------- glutEstablishOverlay :: MonadIO m => m () glutEstablishOverlay = liftIO $ dyn_glutEstablishOverlay ptr_glutEstablishOverlay foreign import CALLCONV "dynamic" dyn_glutEstablishOverlay :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutEstablishOverlay #-} ptr_glutEstablishOverlay :: FunPtr a ptr_glutEstablishOverlay = unsafePerformIO $ getAPIEntry "glutEstablishOverlay" -- glutExit -------------------------------------------------------------------- glutExit :: MonadIO m => m () glutExit = liftIO $ dyn_glutExit ptr_glutExit foreign import CALLCONV "dynamic" dyn_glutExit :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutExit #-} ptr_glutExit :: FunPtr a ptr_glutExit = unsafePerformIO $ getAPIEntry "glutExit" -- glutExtensionSupported ------------------------------------------------------ glutExtensionSupported :: MonadIO m => Ptr CChar -> m CInt glutExtensionSupported v1 = liftIO $ dyn_glutExtensionSupported ptr_glutExtensionSupported v1 foreign import CALLCONV "dynamic" dyn_glutExtensionSupported :: FunPtr (Ptr CChar -> IO CInt) -> Ptr CChar -> IO CInt {-# NOINLINE ptr_glutExtensionSupported #-} ptr_glutExtensionSupported :: FunPtr a ptr_glutExtensionSupported = unsafePerformIO $ getAPIEntry "glutExtensionSupported" -- glutForceJoystickFunc ------------------------------------------------------- glutForceJoystickFunc :: MonadIO m => m () glutForceJoystickFunc = liftIO $ dyn_glutForceJoystickFunc ptr_glutForceJoystickFunc foreign import CALLCONV "dynamic" dyn_glutForceJoystickFunc :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutForceJoystickFunc #-} ptr_glutForceJoystickFunc :: FunPtr a ptr_glutForceJoystickFunc = unsafePerformIO $ getAPIEntry "glutForceJoystickFunc" -- glutFullScreen -------------------------------------------------------------- glutFullScreen :: MonadIO m => m () glutFullScreen = liftIO $ dyn_glutFullScreen ptr_glutFullScreen foreign import CALLCONV "dynamic" dyn_glutFullScreen :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutFullScreen #-} ptr_glutFullScreen :: FunPtr a ptr_glutFullScreen = unsafePerformIO $ getAPIEntry "glutFullScreen" -- glutFullScreenToggle -------------------------------------------------------- glutFullScreenToggle :: MonadIO m => m () glutFullScreenToggle = liftIO $ dyn_glutFullScreenToggle ptr_glutFullScreenToggle foreign import CALLCONV "dynamic" dyn_glutFullScreenToggle :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutFullScreenToggle #-} ptr_glutFullScreenToggle :: FunPtr a ptr_glutFullScreenToggle = unsafePerformIO $ getAPIEntry "glutFullScreenToggle" -- glutGameModeGet ------------------------------------------------------------- glutGameModeGet :: MonadIO m => GLenum -> m CInt glutGameModeGet v1 = liftIO $ dyn_glutGameModeGet ptr_glutGameModeGet v1 foreign import CALLCONV "dynamic" dyn_glutGameModeGet :: FunPtr (GLenum -> IO CInt) -> GLenum -> IO CInt {-# NOINLINE ptr_glutGameModeGet #-} ptr_glutGameModeGet :: FunPtr a ptr_glutGameModeGet = unsafePerformIO $ getAPIEntry "glutGameModeGet" -- glutGameModeString ---------------------------------------------------------- glutGameModeString :: MonadIO m => Ptr CChar -> m () glutGameModeString v1 = liftIO $ dyn_glutGameModeString ptr_glutGameModeString v1 foreign import CALLCONV "dynamic" dyn_glutGameModeString :: FunPtr (Ptr CChar -> IO ()) -> Ptr CChar -> IO () {-# NOINLINE ptr_glutGameModeString #-} ptr_glutGameModeString :: FunPtr a ptr_glutGameModeString = unsafePerformIO $ getAPIEntry "glutGameModeString" -- glutGet --------------------------------------------------------------------- glutGet :: MonadIO m => GLenum -> m CInt glutGet v1 = liftIO $ dyn_glutGet ptr_glutGet v1 foreign import CALLCONV "dynamic" dyn_glutGet :: FunPtr (GLenum -> IO CInt) -> GLenum -> IO CInt {-# NOINLINE ptr_glutGet #-} ptr_glutGet :: FunPtr a ptr_glutGet = unsafePerformIO $ getAPIEntry "glutGet" -- glutGetColor ---------------------------------------------------------------- glutGetColor :: MonadIO m => CInt -> CInt -> m GLfloat glutGetColor v1 v2 = liftIO $ dyn_glutGetColor ptr_glutGetColor v1 v2 foreign import CALLCONV "dynamic" dyn_glutGetColor :: FunPtr (CInt -> CInt -> IO GLfloat) -> CInt -> CInt -> IO GLfloat {-# NOINLINE ptr_glutGetColor #-} ptr_glutGetColor :: FunPtr a ptr_glutGetColor = unsafePerformIO $ getAPIEntry "glutGetColor" -- glutGetMenu ----------------------------------------------------------------- glutGetMenu :: MonadIO m => m CInt glutGetMenu = liftIO $ dyn_glutGetMenu ptr_glutGetMenu foreign import CALLCONV "dynamic" dyn_glutGetMenu :: FunPtr (IO CInt) -> IO CInt {-# NOINLINE ptr_glutGetMenu #-} ptr_glutGetMenu :: FunPtr a ptr_glutGetMenu = unsafePerformIO $ getAPIEntry "glutGetMenu" -- glutGetMenuData ------------------------------------------------------------- glutGetMenuData :: MonadIO m => m (Ptr a) glutGetMenuData = liftIO $ dyn_glutGetMenuData ptr_glutGetMenuData foreign import CALLCONV "dynamic" dyn_glutGetMenuData :: FunPtr (IO (Ptr a)) -> IO (Ptr a) {-# NOINLINE ptr_glutGetMenuData #-} ptr_glutGetMenuData :: FunPtr a ptr_glutGetMenuData = unsafePerformIO $ getAPIEntry "glutGetMenuData" -- glutGetModeValues ----------------------------------------------------------- glutGetModeValues :: MonadIO m => GLenum -> Ptr CInt -> m (Ptr CInt) glutGetModeValues v1 v2 = liftIO $ dyn_glutGetModeValues ptr_glutGetModeValues v1 v2 foreign import CALLCONV "dynamic" dyn_glutGetModeValues :: FunPtr (GLenum -> Ptr CInt -> IO (Ptr CInt)) -> GLenum -> Ptr CInt -> IO (Ptr CInt) {-# NOINLINE ptr_glutGetModeValues #-} ptr_glutGetModeValues :: FunPtr a ptr_glutGetModeValues = unsafePerformIO $ getAPIEntry "glutGetModeValues" -- glutGetModifiers ------------------------------------------------------------ glutGetModifiers :: MonadIO m => m CInt glutGetModifiers = liftIO $ dyn_glutGetModifiers ptr_glutGetModifiers foreign import CALLCONV "dynamic" dyn_glutGetModifiers :: FunPtr (IO CInt) -> IO CInt {-# NOINLINE ptr_glutGetModifiers #-} ptr_glutGetModifiers :: FunPtr a ptr_glutGetModifiers = unsafePerformIO $ getAPIEntry "glutGetModifiers" -- glutGetProcAddress ---------------------------------------------------------- glutGetProcAddress :: MonadIO m => Ptr CChar -> m (FunPtr a) glutGetProcAddress v1 = liftIO $ dyn_glutGetProcAddress ptr_glutGetProcAddress v1 foreign import CALLCONV "dynamic" dyn_glutGetProcAddress :: FunPtr (Ptr CChar -> IO (FunPtr a)) -> Ptr CChar -> IO (FunPtr a) {-# NOINLINE ptr_glutGetProcAddress #-} ptr_glutGetProcAddress :: FunPtr a ptr_glutGetProcAddress = unsafePerformIO $ getAPIEntry "glutGetProcAddress" -- glutGetWindow --------------------------------------------------------------- glutGetWindow :: MonadIO m => m CInt glutGetWindow = liftIO $ dyn_glutGetWindow ptr_glutGetWindow foreign import CALLCONV "dynamic" dyn_glutGetWindow :: FunPtr (IO CInt) -> IO CInt {-# NOINLINE ptr_glutGetWindow #-} ptr_glutGetWindow :: FunPtr a ptr_glutGetWindow = unsafePerformIO $ getAPIEntry "glutGetWindow" -- glutGetWindowData ----------------------------------------------------------- glutGetWindowData :: MonadIO m => m (Ptr a) glutGetWindowData = liftIO $ dyn_glutGetWindowData ptr_glutGetWindowData foreign import CALLCONV "dynamic" dyn_glutGetWindowData :: FunPtr (IO (Ptr a)) -> IO (Ptr a) {-# NOINLINE ptr_glutGetWindowData #-} ptr_glutGetWindowData :: FunPtr a ptr_glutGetWindowData = unsafePerformIO $ getAPIEntry "glutGetWindowData" -- glutHideOverlay ------------------------------------------------------------- glutHideOverlay :: MonadIO m => m () glutHideOverlay = liftIO $ dyn_glutHideOverlay ptr_glutHideOverlay foreign import CALLCONV "dynamic" dyn_glutHideOverlay :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutHideOverlay #-} ptr_glutHideOverlay :: FunPtr a ptr_glutHideOverlay = unsafePerformIO $ getAPIEntry "glutHideOverlay" -- glutHideWindow -------------------------------------------------------------- glutHideWindow :: MonadIO m => m () glutHideWindow = liftIO $ dyn_glutHideWindow ptr_glutHideWindow foreign import CALLCONV "dynamic" dyn_glutHideWindow :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutHideWindow #-} ptr_glutHideWindow :: FunPtr a ptr_glutHideWindow = unsafePerformIO $ getAPIEntry "glutHideWindow" -- glutIconifyWindow ----------------------------------------------------------- glutIconifyWindow :: MonadIO m => m () glutIconifyWindow = liftIO $ dyn_glutIconifyWindow ptr_glutIconifyWindow foreign import CALLCONV "dynamic" dyn_glutIconifyWindow :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutIconifyWindow #-} ptr_glutIconifyWindow :: FunPtr a ptr_glutIconifyWindow = unsafePerformIO $ getAPIEntry "glutIconifyWindow" -- glutIdleFunc ---------------------------------------------------------------- glutIdleFunc :: MonadIO m => FunPtr IdleFunc -> m () glutIdleFunc v1 = liftIO $ dyn_glutIdleFunc ptr_glutIdleFunc v1 foreign import CALLCONV "dynamic" dyn_glutIdleFunc :: FunPtr (FunPtr IdleFunc -> IO ()) -> FunPtr IdleFunc -> IO () {-# NOINLINE ptr_glutIdleFunc #-} ptr_glutIdleFunc :: FunPtr a ptr_glutIdleFunc = unsafePerformIO $ getAPIEntry "glutIdleFunc" -- glutIgnoreKeyRepeat --------------------------------------------------------- glutIgnoreKeyRepeat :: MonadIO m => CInt -> m () glutIgnoreKeyRepeat v1 = liftIO $ dyn_glutIgnoreKeyRepeat ptr_glutIgnoreKeyRepeat v1 foreign import CALLCONV "dynamic" dyn_glutIgnoreKeyRepeat :: FunPtr (CInt -> IO ()) -> CInt -> IO () {-# NOINLINE ptr_glutIgnoreKeyRepeat #-} ptr_glutIgnoreKeyRepeat :: FunPtr a ptr_glutIgnoreKeyRepeat = unsafePerformIO $ getAPIEntry "glutIgnoreKeyRepeat" -- glutInit -------------------------------------------------------------------- glutInit :: MonadIO m => Ptr CInt -> Ptr (Ptr CChar) -> m () glutInit v1 v2 = liftIO $ dyn_glutInit ptr_glutInit v1 v2 foreign import CALLCONV "dynamic" dyn_glutInit :: FunPtr (Ptr CInt -> Ptr (Ptr CChar) -> IO ()) -> Ptr CInt -> Ptr (Ptr CChar) -> IO () {-# NOINLINE ptr_glutInit #-} ptr_glutInit :: FunPtr a ptr_glutInit = unsafePerformIO $ getAPIEntry "glutInit" -- glutInitContextFlags -------------------------------------------------------- glutInitContextFlags :: MonadIO m => CInt -> m () glutInitContextFlags v1 = liftIO $ dyn_glutInitContextFlags ptr_glutInitContextFlags v1 foreign import CALLCONV "dynamic" dyn_glutInitContextFlags :: FunPtr (CInt -> IO ()) -> CInt -> IO () {-# NOINLINE ptr_glutInitContextFlags #-} ptr_glutInitContextFlags :: FunPtr a ptr_glutInitContextFlags = unsafePerformIO $ getAPIEntry "glutInitContextFlags" -- glutInitContextFunc --------------------------------------------------------- glutInitContextFunc :: MonadIO m => FunPtr InitContextFunc -> m () glutInitContextFunc v1 = liftIO $ dyn_glutInitContextFunc ptr_glutInitContextFunc v1 foreign import CALLCONV "dynamic" dyn_glutInitContextFunc :: FunPtr (FunPtr InitContextFunc -> IO ()) -> FunPtr InitContextFunc -> IO () {-# NOINLINE ptr_glutInitContextFunc #-} ptr_glutInitContextFunc :: FunPtr a ptr_glutInitContextFunc = unsafePerformIO $ getAPIEntry "glutInitContextFunc" -- glutInitContextProfile ------------------------------------------------------ glutInitContextProfile :: MonadIO m => CInt -> m () glutInitContextProfile v1 = liftIO $ dyn_glutInitContextProfile ptr_glutInitContextProfile v1 foreign import CALLCONV "dynamic" dyn_glutInitContextProfile :: FunPtr (CInt -> IO ()) -> CInt -> IO () {-# NOINLINE ptr_glutInitContextProfile #-} ptr_glutInitContextProfile :: FunPtr a ptr_glutInitContextProfile = unsafePerformIO $ getAPIEntry "glutInitContextProfile" -- glutInitContextVersion ------------------------------------------------------ glutInitContextVersion :: MonadIO m => CInt -> CInt -> m () glutInitContextVersion v1 v2 = liftIO $ dyn_glutInitContextVersion ptr_glutInitContextVersion v1 v2 foreign import CALLCONV "dynamic" dyn_glutInitContextVersion :: FunPtr (CInt -> CInt -> IO ()) -> CInt -> CInt -> IO () {-# NOINLINE ptr_glutInitContextVersion #-} ptr_glutInitContextVersion :: FunPtr a ptr_glutInitContextVersion = unsafePerformIO $ getAPIEntry "glutInitContextVersion" -- glutInitDisplayMode --------------------------------------------------------- glutInitDisplayMode :: MonadIO m => CUInt -> m () glutInitDisplayMode v1 = liftIO $ dyn_glutInitDisplayMode ptr_glutInitDisplayMode v1 foreign import CALLCONV "dynamic" dyn_glutInitDisplayMode :: FunPtr (CUInt -> IO ()) -> CUInt -> IO () {-# NOINLINE ptr_glutInitDisplayMode #-} ptr_glutInitDisplayMode :: FunPtr a ptr_glutInitDisplayMode = unsafePerformIO $ getAPIEntry "glutInitDisplayMode" -- glutInitDisplayString ------------------------------------------------------- glutInitDisplayString :: MonadIO m => Ptr CChar -> m () glutInitDisplayString v1 = liftIO $ dyn_glutInitDisplayString ptr_glutInitDisplayString v1 foreign import CALLCONV "dynamic" dyn_glutInitDisplayString :: FunPtr (Ptr CChar -> IO ()) -> Ptr CChar -> IO () {-# NOINLINE ptr_glutInitDisplayString #-} ptr_glutInitDisplayString :: FunPtr a ptr_glutInitDisplayString = unsafePerformIO $ getAPIEntry "glutInitDisplayString" -- glutInitWindowPosition ------------------------------------------------------ glutInitWindowPosition :: MonadIO m => CInt -> CInt -> m () glutInitWindowPosition v1 v2 = liftIO $ dyn_glutInitWindowPosition ptr_glutInitWindowPosition v1 v2 foreign import CALLCONV "dynamic" dyn_glutInitWindowPosition :: FunPtr (CInt -> CInt -> IO ()) -> CInt -> CInt -> IO () {-# NOINLINE ptr_glutInitWindowPosition #-} ptr_glutInitWindowPosition :: FunPtr a ptr_glutInitWindowPosition = unsafePerformIO $ getAPIEntry "glutInitWindowPosition" -- glutInitWindowSize ---------------------------------------------------------- glutInitWindowSize :: MonadIO m => CInt -> CInt -> m () glutInitWindowSize v1 v2 = liftIO $ dyn_glutInitWindowSize ptr_glutInitWindowSize v1 v2 foreign import CALLCONV "dynamic" dyn_glutInitWindowSize :: FunPtr (CInt -> CInt -> IO ()) -> CInt -> CInt -> IO () {-# NOINLINE ptr_glutInitWindowSize #-} ptr_glutInitWindowSize :: FunPtr a ptr_glutInitWindowSize = unsafePerformIO $ getAPIEntry "glutInitWindowSize" -- glutJoystickFunc ------------------------------------------------------------ glutJoystickFunc :: MonadIO m => FunPtr JoystickFunc -> CInt -> m () glutJoystickFunc v1 v2 = liftIO $ dyn_glutJoystickFunc ptr_glutJoystickFunc v1 v2 foreign import CALLCONV "dynamic" dyn_glutJoystickFunc :: FunPtr (FunPtr JoystickFunc -> CInt -> IO ()) -> FunPtr JoystickFunc -> CInt -> IO () {-# NOINLINE ptr_glutJoystickFunc #-} ptr_glutJoystickFunc :: FunPtr a ptr_glutJoystickFunc = unsafePerformIO $ getAPIEntry "glutJoystickFunc" -- glutKeyboardFunc ------------------------------------------------------------ glutKeyboardFunc :: MonadIO m => FunPtr KeyboardFunc -> m () glutKeyboardFunc v1 = liftIO $ dyn_glutKeyboardFunc ptr_glutKeyboardFunc v1 foreign import CALLCONV "dynamic" dyn_glutKeyboardFunc :: FunPtr (FunPtr KeyboardFunc -> IO ()) -> FunPtr KeyboardFunc -> IO () {-# NOINLINE ptr_glutKeyboardFunc #-} ptr_glutKeyboardFunc :: FunPtr a ptr_glutKeyboardFunc = unsafePerformIO $ getAPIEntry "glutKeyboardFunc" -- glutKeyboardUpFunc ---------------------------------------------------------- glutKeyboardUpFunc :: MonadIO m => FunPtr KeyboardUpFunc -> m () glutKeyboardUpFunc v1 = liftIO $ dyn_glutKeyboardUpFunc ptr_glutKeyboardUpFunc v1 foreign import CALLCONV "dynamic" dyn_glutKeyboardUpFunc :: FunPtr (FunPtr KeyboardUpFunc -> IO ()) -> FunPtr KeyboardUpFunc -> IO () {-# NOINLINE ptr_glutKeyboardUpFunc #-} ptr_glutKeyboardUpFunc :: FunPtr a ptr_glutKeyboardUpFunc = unsafePerformIO $ getAPIEntry "glutKeyboardUpFunc" -- glutLayerGet ---------------------------------------------------------------- glutLayerGet :: MonadIO m => GLenum -> m CInt glutLayerGet v1 = liftIO $ dyn_glutLayerGet ptr_glutLayerGet v1 foreign import CALLCONV "dynamic" dyn_glutLayerGet :: FunPtr (GLenum -> IO CInt) -> GLenum -> IO CInt {-# NOINLINE ptr_glutLayerGet #-} ptr_glutLayerGet :: FunPtr a ptr_glutLayerGet = unsafePerformIO $ getAPIEntry "glutLayerGet" -- glutLeaveFullScreen --------------------------------------------------------- glutLeaveFullScreen :: MonadIO m => m () glutLeaveFullScreen = liftIO $ dyn_glutLeaveFullScreen ptr_glutLeaveFullScreen foreign import CALLCONV "dynamic" dyn_glutLeaveFullScreen :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutLeaveFullScreen #-} ptr_glutLeaveFullScreen :: FunPtr a ptr_glutLeaveFullScreen = unsafePerformIO $ getAPIEntry "glutLeaveFullScreen" -- glutLeaveGameMode ----------------------------------------------------------- glutLeaveGameMode :: MonadIO m => m () glutLeaveGameMode = liftIO $ dyn_glutLeaveGameMode ptr_glutLeaveGameMode foreign import CALLCONV "dynamic" dyn_glutLeaveGameMode :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutLeaveGameMode #-} ptr_glutLeaveGameMode :: FunPtr a ptr_glutLeaveGameMode = unsafePerformIO $ getAPIEntry "glutLeaveGameMode" -- glutLeaveMainLoop ----------------------------------------------------------- glutLeaveMainLoop :: MonadIO m => m () glutLeaveMainLoop = liftIO $ dyn_glutLeaveMainLoop ptr_glutLeaveMainLoop foreign import CALLCONV "dynamic" dyn_glutLeaveMainLoop :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutLeaveMainLoop #-} ptr_glutLeaveMainLoop :: FunPtr a ptr_glutLeaveMainLoop = unsafePerformIO $ getAPIEntry "glutLeaveMainLoop" -- glutMainLoop ---------------------------------------------------------------- glutMainLoop :: MonadIO m => m () glutMainLoop = liftIO $ dyn_glutMainLoop ptr_glutMainLoop foreign import CALLCONV "dynamic" dyn_glutMainLoop :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutMainLoop #-} ptr_glutMainLoop :: FunPtr a ptr_glutMainLoop = unsafePerformIO $ getAPIEntry "glutMainLoop" -- glutMainLoopEvent ----------------------------------------------------------- glutMainLoopEvent :: MonadIO m => m () glutMainLoopEvent = liftIO $ dyn_glutMainLoopEvent ptr_glutMainLoopEvent foreign import CALLCONV "dynamic" dyn_glutMainLoopEvent :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutMainLoopEvent #-} ptr_glutMainLoopEvent :: FunPtr a ptr_glutMainLoopEvent = unsafePerformIO $ getAPIEntry "glutMainLoopEvent" -- glutMenuDestroyFunc --------------------------------------------------------- glutMenuDestroyFunc :: MonadIO m => FunPtr MenuDestroyFunc -> m () glutMenuDestroyFunc v1 = liftIO $ dyn_glutMenuDestroyFunc ptr_glutMenuDestroyFunc v1 foreign import CALLCONV "dynamic" dyn_glutMenuDestroyFunc :: FunPtr (FunPtr MenuDestroyFunc -> IO ()) -> FunPtr MenuDestroyFunc -> IO () {-# NOINLINE ptr_glutMenuDestroyFunc #-} ptr_glutMenuDestroyFunc :: FunPtr a ptr_glutMenuDestroyFunc = unsafePerformIO $ getAPIEntry "glutMenuDestroyFunc" -- glutMenuStateFunc ----------------------------------------------------------- glutMenuStateFunc :: MonadIO m => FunPtr MenuStateFunc -> m () glutMenuStateFunc v1 = liftIO $ dyn_glutMenuStateFunc ptr_glutMenuStateFunc v1 foreign import CALLCONV "dynamic" dyn_glutMenuStateFunc :: FunPtr (FunPtr MenuStateFunc -> IO ()) -> FunPtr MenuStateFunc -> IO () {-# NOINLINE ptr_glutMenuStateFunc #-} ptr_glutMenuStateFunc :: FunPtr a ptr_glutMenuStateFunc = unsafePerformIO $ getAPIEntry "glutMenuStateFunc" -- glutMenuStatusFunc ---------------------------------------------------------- glutMenuStatusFunc :: MonadIO m => FunPtr MenuStatusFunc -> m () glutMenuStatusFunc v1 = liftIO $ dyn_glutMenuStatusFunc ptr_glutMenuStatusFunc v1 foreign import CALLCONV "dynamic" dyn_glutMenuStatusFunc :: FunPtr (FunPtr MenuStatusFunc -> IO ()) -> FunPtr MenuStatusFunc -> IO () {-# NOINLINE ptr_glutMenuStatusFunc #-} ptr_glutMenuStatusFunc :: FunPtr a ptr_glutMenuStatusFunc = unsafePerformIO $ getAPIEntry "glutMenuStatusFunc" -- glutMotionFunc -------------------------------------------------------------- glutMotionFunc :: MonadIO m => FunPtr MotionFunc -> m () glutMotionFunc v1 = liftIO $ dyn_glutMotionFunc ptr_glutMotionFunc v1 foreign import CALLCONV "dynamic" dyn_glutMotionFunc :: FunPtr (FunPtr MotionFunc -> IO ()) -> FunPtr MotionFunc -> IO () {-# NOINLINE ptr_glutMotionFunc #-} ptr_glutMotionFunc :: FunPtr a ptr_glutMotionFunc = unsafePerformIO $ getAPIEntry "glutMotionFunc" -- glutMouseFunc --------------------------------------------------------------- glutMouseFunc :: MonadIO m => FunPtr MouseFunc -> m () glutMouseFunc v1 = liftIO $ dyn_glutMouseFunc ptr_glutMouseFunc v1 foreign import CALLCONV "dynamic" dyn_glutMouseFunc :: FunPtr (FunPtr MouseFunc -> IO ()) -> FunPtr MouseFunc -> IO () {-# NOINLINE ptr_glutMouseFunc #-} ptr_glutMouseFunc :: FunPtr a ptr_glutMouseFunc = unsafePerformIO $ getAPIEntry "glutMouseFunc" -- glutMouseWheelFunc ---------------------------------------------------------- glutMouseWheelFunc :: MonadIO m => FunPtr MouseWheelFunc -> m () glutMouseWheelFunc v1 = liftIO $ dyn_glutMouseWheelFunc ptr_glutMouseWheelFunc v1 foreign import CALLCONV "dynamic" dyn_glutMouseWheelFunc :: FunPtr (FunPtr MouseWheelFunc -> IO ()) -> FunPtr MouseWheelFunc -> IO () {-# NOINLINE ptr_glutMouseWheelFunc #-} ptr_glutMouseWheelFunc :: FunPtr a ptr_glutMouseWheelFunc = unsafePerformIO $ getAPIEntry "glutMouseWheelFunc" -- glutMultiButtonFunc --------------------------------------------------------- glutMultiButtonFunc :: MonadIO m => FunPtr MultiButtonFunc -> m () glutMultiButtonFunc v1 = liftIO $ dyn_glutMultiButtonFunc ptr_glutMultiButtonFunc v1 foreign import CALLCONV "dynamic" dyn_glutMultiButtonFunc :: FunPtr (FunPtr MultiButtonFunc -> IO ()) -> FunPtr MultiButtonFunc -> IO () {-# NOINLINE ptr_glutMultiButtonFunc #-} ptr_glutMultiButtonFunc :: FunPtr a ptr_glutMultiButtonFunc = unsafePerformIO $ getAPIEntry "glutMultiButtonFunc" -- glutMultiEntryFunc ---------------------------------------------------------- glutMultiEntryFunc :: MonadIO m => FunPtr MultiEntryFunc -> m () glutMultiEntryFunc v1 = liftIO $ dyn_glutMultiEntryFunc ptr_glutMultiEntryFunc v1 foreign import CALLCONV "dynamic" dyn_glutMultiEntryFunc :: FunPtr (FunPtr MultiEntryFunc -> IO ()) -> FunPtr MultiEntryFunc -> IO () {-# NOINLINE ptr_glutMultiEntryFunc #-} ptr_glutMultiEntryFunc :: FunPtr a ptr_glutMultiEntryFunc = unsafePerformIO $ getAPIEntry "glutMultiEntryFunc" -- glutMultiMotionFunc --------------------------------------------------------- glutMultiMotionFunc :: MonadIO m => FunPtr MultiMotionFunc -> m () glutMultiMotionFunc v1 = liftIO $ dyn_glutMultiMotionFunc ptr_glutMultiMotionFunc v1 foreign import CALLCONV "dynamic" dyn_glutMultiMotionFunc :: FunPtr (FunPtr MultiMotionFunc -> IO ()) -> FunPtr MultiMotionFunc -> IO () {-# NOINLINE ptr_glutMultiMotionFunc #-} ptr_glutMultiMotionFunc :: FunPtr a ptr_glutMultiMotionFunc = unsafePerformIO $ getAPIEntry "glutMultiMotionFunc" -- glutMultiPassiveFunc -------------------------------------------------------- glutMultiPassiveFunc :: MonadIO m => FunPtr MultiPassiveFunc -> m () glutMultiPassiveFunc v1 = liftIO $ dyn_glutMultiPassiveFunc ptr_glutMultiPassiveFunc v1 foreign import CALLCONV "dynamic" dyn_glutMultiPassiveFunc :: FunPtr (FunPtr MultiPassiveFunc -> IO ()) -> FunPtr MultiPassiveFunc -> IO () {-# NOINLINE ptr_glutMultiPassiveFunc #-} ptr_glutMultiPassiveFunc :: FunPtr a ptr_glutMultiPassiveFunc = unsafePerformIO $ getAPIEntry "glutMultiPassiveFunc" -- glutOverlayDisplayFunc ------------------------------------------------------ glutOverlayDisplayFunc :: MonadIO m => FunPtr OverlayDisplayFunc -> m () glutOverlayDisplayFunc v1 = liftIO $ dyn_glutOverlayDisplayFunc ptr_glutOverlayDisplayFunc v1 foreign import CALLCONV "dynamic" dyn_glutOverlayDisplayFunc :: FunPtr (FunPtr OverlayDisplayFunc -> IO ()) -> FunPtr OverlayDisplayFunc -> IO () {-# NOINLINE ptr_glutOverlayDisplayFunc #-} ptr_glutOverlayDisplayFunc :: FunPtr a ptr_glutOverlayDisplayFunc = unsafePerformIO $ getAPIEntry "glutOverlayDisplayFunc" -- glutPassiveMotionFunc ------------------------------------------------------- glutPassiveMotionFunc :: MonadIO m => FunPtr PassiveMotionFunc -> m () glutPassiveMotionFunc v1 = liftIO $ dyn_glutPassiveMotionFunc ptr_glutPassiveMotionFunc v1 foreign import CALLCONV "dynamic" dyn_glutPassiveMotionFunc :: FunPtr (FunPtr PassiveMotionFunc -> IO ()) -> FunPtr PassiveMotionFunc -> IO () {-# NOINLINE ptr_glutPassiveMotionFunc #-} ptr_glutPassiveMotionFunc :: FunPtr a ptr_glutPassiveMotionFunc = unsafePerformIO $ getAPIEntry "glutPassiveMotionFunc" -- glutPopWindow --------------------------------------------------------------- glutPopWindow :: MonadIO m => m () glutPopWindow = liftIO $ dyn_glutPopWindow ptr_glutPopWindow foreign import CALLCONV "dynamic" dyn_glutPopWindow :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutPopWindow #-} ptr_glutPopWindow :: FunPtr a ptr_glutPopWindow = unsafePerformIO $ getAPIEntry "glutPopWindow" -- glutPositionFunc ------------------------------------------------------------ glutPositionFunc :: MonadIO m => FunPtr PositionFunc -> m () glutPositionFunc v1 = liftIO $ dyn_glutPositionFunc ptr_glutPositionFunc v1 foreign import CALLCONV "dynamic" dyn_glutPositionFunc :: FunPtr (FunPtr PositionFunc -> IO ()) -> FunPtr PositionFunc -> IO () {-# NOINLINE ptr_glutPositionFunc #-} ptr_glutPositionFunc :: FunPtr a ptr_glutPositionFunc = unsafePerformIO $ getAPIEntry "glutPositionFunc" -- glutPositionWindow ---------------------------------------------------------- glutPositionWindow :: MonadIO m => CInt -> CInt -> m () glutPositionWindow v1 v2 = liftIO $ dyn_glutPositionWindow ptr_glutPositionWindow v1 v2 foreign import CALLCONV "dynamic" dyn_glutPositionWindow :: FunPtr (CInt -> CInt -> IO ()) -> CInt -> CInt -> IO () {-# NOINLINE ptr_glutPositionWindow #-} ptr_glutPositionWindow :: FunPtr a ptr_glutPositionWindow = unsafePerformIO $ getAPIEntry "glutPositionWindow" -- glutPostOverlayRedisplay ---------------------------------------------------- glutPostOverlayRedisplay :: MonadIO m => m () glutPostOverlayRedisplay = liftIO $ dyn_glutPostOverlayRedisplay ptr_glutPostOverlayRedisplay foreign import CALLCONV "dynamic" dyn_glutPostOverlayRedisplay :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutPostOverlayRedisplay #-} ptr_glutPostOverlayRedisplay :: FunPtr a ptr_glutPostOverlayRedisplay = unsafePerformIO $ getAPIEntry "glutPostOverlayRedisplay" -- glutPostRedisplay ----------------------------------------------------------- glutPostRedisplay :: MonadIO m => m () glutPostRedisplay = liftIO $ dyn_glutPostRedisplay ptr_glutPostRedisplay foreign import CALLCONV "dynamic" dyn_glutPostRedisplay :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutPostRedisplay #-} ptr_glutPostRedisplay :: FunPtr a ptr_glutPostRedisplay = unsafePerformIO $ getAPIEntry "glutPostRedisplay" -- glutPostWindowOverlayRedisplay ---------------------------------------------- glutPostWindowOverlayRedisplay :: MonadIO m => CInt -> m () glutPostWindowOverlayRedisplay v1 = liftIO $ dyn_glutPostWindowOverlayRedisplay ptr_glutPostWindowOverlayRedisplay v1 foreign import CALLCONV "dynamic" dyn_glutPostWindowOverlayRedisplay :: FunPtr (CInt -> IO ()) -> CInt -> IO () {-# NOINLINE ptr_glutPostWindowOverlayRedisplay #-} ptr_glutPostWindowOverlayRedisplay :: FunPtr a ptr_glutPostWindowOverlayRedisplay = unsafePerformIO $ getAPIEntry "glutPostWindowOverlayRedisplay" -- glutPostWindowRedisplay ----------------------------------------------------- glutPostWindowRedisplay :: MonadIO m => CInt -> m () glutPostWindowRedisplay v1 = liftIO $ dyn_glutPostWindowRedisplay ptr_glutPostWindowRedisplay v1 foreign import CALLCONV "dynamic" dyn_glutPostWindowRedisplay :: FunPtr (CInt -> IO ()) -> CInt -> IO () {-# NOINLINE ptr_glutPostWindowRedisplay #-} ptr_glutPostWindowRedisplay :: FunPtr a ptr_glutPostWindowRedisplay = unsafePerformIO $ getAPIEntry "glutPostWindowRedisplay" -- glutPushWindow -------------------------------------------------------------- glutPushWindow :: MonadIO m => m () glutPushWindow = liftIO $ dyn_glutPushWindow ptr_glutPushWindow foreign import CALLCONV "dynamic" dyn_glutPushWindow :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutPushWindow #-} ptr_glutPushWindow :: FunPtr a ptr_glutPushWindow = unsafePerformIO $ getAPIEntry "glutPushWindow" -- glutRemoveMenuItem ---------------------------------------------------------- glutRemoveMenuItem :: MonadIO m => CInt -> m () glutRemoveMenuItem v1 = liftIO $ dyn_glutRemoveMenuItem ptr_glutRemoveMenuItem v1 foreign import CALLCONV "dynamic" dyn_glutRemoveMenuItem :: FunPtr (CInt -> IO ()) -> CInt -> IO () {-# NOINLINE ptr_glutRemoveMenuItem #-} ptr_glutRemoveMenuItem :: FunPtr a ptr_glutRemoveMenuItem = unsafePerformIO $ getAPIEntry "glutRemoveMenuItem" -- glutRemoveOverlay ----------------------------------------------------------- glutRemoveOverlay :: MonadIO m => m () glutRemoveOverlay = liftIO $ dyn_glutRemoveOverlay ptr_glutRemoveOverlay foreign import CALLCONV "dynamic" dyn_glutRemoveOverlay :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutRemoveOverlay #-} ptr_glutRemoveOverlay :: FunPtr a ptr_glutRemoveOverlay = unsafePerformIO $ getAPIEntry "glutRemoveOverlay" -- glutReportErrors ------------------------------------------------------------ glutReportErrors :: MonadIO m => m () glutReportErrors = liftIO $ dyn_glutReportErrors ptr_glutReportErrors foreign import CALLCONV "dynamic" dyn_glutReportErrors :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutReportErrors #-} ptr_glutReportErrors :: FunPtr a ptr_glutReportErrors = unsafePerformIO $ getAPIEntry "glutReportErrors" -- glutReshapeFunc ------------------------------------------------------------- glutReshapeFunc :: MonadIO m => FunPtr ReshapeFunc -> m () glutReshapeFunc v1 = liftIO $ dyn_glutReshapeFunc ptr_glutReshapeFunc v1 foreign import CALLCONV "dynamic" dyn_glutReshapeFunc :: FunPtr (FunPtr ReshapeFunc -> IO ()) -> FunPtr ReshapeFunc -> IO () {-# NOINLINE ptr_glutReshapeFunc #-} ptr_glutReshapeFunc :: FunPtr a ptr_glutReshapeFunc = unsafePerformIO $ getAPIEntry "glutReshapeFunc" -- glutReshapeWindow ----------------------------------------------------------- glutReshapeWindow :: MonadIO m => CInt -> CInt -> m () glutReshapeWindow v1 v2 = liftIO $ dyn_glutReshapeWindow ptr_glutReshapeWindow v1 v2 foreign import CALLCONV "dynamic" dyn_glutReshapeWindow :: FunPtr (CInt -> CInt -> IO ()) -> CInt -> CInt -> IO () {-# NOINLINE ptr_glutReshapeWindow #-} ptr_glutReshapeWindow :: FunPtr a ptr_glutReshapeWindow = unsafePerformIO $ getAPIEntry "glutReshapeWindow" -- glutSetColor ---------------------------------------------------------------- glutSetColor :: MonadIO m => CInt -> GLfloat -> GLfloat -> GLfloat -> m () glutSetColor v1 v2 v3 v4 = liftIO $ dyn_glutSetColor ptr_glutSetColor v1 v2 v3 v4 foreign import CALLCONV "dynamic" dyn_glutSetColor :: FunPtr (CInt -> GLfloat -> GLfloat -> GLfloat -> IO ()) -> CInt -> GLfloat -> GLfloat -> GLfloat -> IO () {-# NOINLINE ptr_glutSetColor #-} ptr_glutSetColor :: FunPtr a ptr_glutSetColor = unsafePerformIO $ getAPIEntry "glutSetColor" -- glutSetCursor --------------------------------------------------------------- glutSetCursor :: MonadIO m => CInt -> m () glutSetCursor v1 = liftIO $ dyn_glutSetCursor ptr_glutSetCursor v1 foreign import CALLCONV "dynamic" dyn_glutSetCursor :: FunPtr (CInt -> IO ()) -> CInt -> IO () {-# NOINLINE ptr_glutSetCursor #-} ptr_glutSetCursor :: FunPtr a ptr_glutSetCursor = unsafePerformIO $ getAPIEntry "glutSetCursor" -- glutSetIconTitle ------------------------------------------------------------ glutSetIconTitle :: MonadIO m => Ptr CChar -> m () glutSetIconTitle v1 = liftIO $ dyn_glutSetIconTitle ptr_glutSetIconTitle v1 foreign import CALLCONV "dynamic" dyn_glutSetIconTitle :: FunPtr (Ptr CChar -> IO ()) -> Ptr CChar -> IO () {-# NOINLINE ptr_glutSetIconTitle #-} ptr_glutSetIconTitle :: FunPtr a ptr_glutSetIconTitle = unsafePerformIO $ getAPIEntry "glutSetIconTitle" -- glutSetKeyRepeat ------------------------------------------------------------ glutSetKeyRepeat :: MonadIO m => CInt -> m () glutSetKeyRepeat v1 = liftIO $ dyn_glutSetKeyRepeat ptr_glutSetKeyRepeat v1 foreign import CALLCONV "dynamic" dyn_glutSetKeyRepeat :: FunPtr (CInt -> IO ()) -> CInt -> IO () {-# NOINLINE ptr_glutSetKeyRepeat #-} ptr_glutSetKeyRepeat :: FunPtr a ptr_glutSetKeyRepeat = unsafePerformIO $ getAPIEntry "glutSetKeyRepeat" -- glutSetMenu ----------------------------------------------------------------- glutSetMenu :: MonadIO m => CInt -> m () glutSetMenu v1 = liftIO $ dyn_glutSetMenu ptr_glutSetMenu v1 foreign import CALLCONV "dynamic" dyn_glutSetMenu :: FunPtr (CInt -> IO ()) -> CInt -> IO () {-# NOINLINE ptr_glutSetMenu #-} ptr_glutSetMenu :: FunPtr a ptr_glutSetMenu = unsafePerformIO $ getAPIEntry "glutSetMenu" -- glutSetMenuData ------------------------------------------------------------- glutSetMenuData :: MonadIO m => Ptr a -> m () glutSetMenuData v1 = liftIO $ dyn_glutSetMenuData ptr_glutSetMenuData v1 foreign import CALLCONV "dynamic" dyn_glutSetMenuData :: FunPtr (Ptr a -> IO ()) -> Ptr a -> IO () {-# NOINLINE ptr_glutSetMenuData #-} ptr_glutSetMenuData :: FunPtr a ptr_glutSetMenuData = unsafePerformIO $ getAPIEntry "glutSetMenuData" -- glutSetMenuFont ------------------------------------------------------------- glutSetMenuFont :: MonadIO m => CInt -> Ptr a -> m () glutSetMenuFont v1 v2 = liftIO $ dyn_glutSetMenuFont ptr_glutSetMenuFont v1 v2 foreign import CALLCONV "dynamic" dyn_glutSetMenuFont :: FunPtr (CInt -> Ptr a -> IO ()) -> CInt -> Ptr a -> IO () {-# NOINLINE ptr_glutSetMenuFont #-} ptr_glutSetMenuFont :: FunPtr a ptr_glutSetMenuFont = unsafePerformIO $ getAPIEntry "glutSetMenuFont" -- glutSetOption --------------------------------------------------------------- glutSetOption :: MonadIO m => GLenum -> CInt -> m () glutSetOption v1 v2 = liftIO $ dyn_glutSetOption ptr_glutSetOption v1 v2 foreign import CALLCONV "dynamic" dyn_glutSetOption :: FunPtr (GLenum -> CInt -> IO ()) -> GLenum -> CInt -> IO () {-# NOINLINE ptr_glutSetOption #-} ptr_glutSetOption :: FunPtr a ptr_glutSetOption = unsafePerformIO $ getAPIEntry "glutSetOption" -- glutSetVertexAttribCoord3 --------------------------------------------------- glutSetVertexAttribCoord3 :: MonadIO m => GLint -> m () glutSetVertexAttribCoord3 v1 = liftIO $ dyn_glutSetVertexAttribCoord3 ptr_glutSetVertexAttribCoord3 v1 foreign import CALLCONV "dynamic" dyn_glutSetVertexAttribCoord3 :: FunPtr (GLint -> IO ()) -> GLint -> IO () {-# NOINLINE ptr_glutSetVertexAttribCoord3 #-} ptr_glutSetVertexAttribCoord3 :: FunPtr a ptr_glutSetVertexAttribCoord3 = unsafePerformIO $ getAPIEntry "glutSetVertexAttribCoord3" -- glutSetVertexAttribNormal --------------------------------------------------- glutSetVertexAttribNormal :: MonadIO m => GLint -> m () glutSetVertexAttribNormal v1 = liftIO $ dyn_glutSetVertexAttribNormal ptr_glutSetVertexAttribNormal v1 foreign import CALLCONV "dynamic" dyn_glutSetVertexAttribNormal :: FunPtr (GLint -> IO ()) -> GLint -> IO () {-# NOINLINE ptr_glutSetVertexAttribNormal #-} ptr_glutSetVertexAttribNormal :: FunPtr a ptr_glutSetVertexAttribNormal = unsafePerformIO $ getAPIEntry "glutSetVertexAttribNormal" -- glutSetVertexAttribTexCoord2 ------------------------------------------------ glutSetVertexAttribTexCoord2 :: MonadIO m => GLint -> m () glutSetVertexAttribTexCoord2 v1 = liftIO $ dyn_glutSetVertexAttribTexCoord2 ptr_glutSetVertexAttribTexCoord2 v1 foreign import CALLCONV "dynamic" dyn_glutSetVertexAttribTexCoord2 :: FunPtr (GLint -> IO ()) -> GLint -> IO () {-# NOINLINE ptr_glutSetVertexAttribTexCoord2 #-} ptr_glutSetVertexAttribTexCoord2 :: FunPtr a ptr_glutSetVertexAttribTexCoord2 = unsafePerformIO $ getAPIEntry "glutSetVertexAttribTexCoord2" -- glutSetWindow --------------------------------------------------------------- glutSetWindow :: MonadIO m => CInt -> m () glutSetWindow v1 = liftIO $ dyn_glutSetWindow ptr_glutSetWindow v1 foreign import CALLCONV "dynamic" dyn_glutSetWindow :: FunPtr (CInt -> IO ()) -> CInt -> IO () {-# NOINLINE ptr_glutSetWindow #-} ptr_glutSetWindow :: FunPtr a ptr_glutSetWindow = unsafePerformIO $ getAPIEntry "glutSetWindow" -- glutSetWindowData ----------------------------------------------------------- glutSetWindowData :: MonadIO m => Ptr a -> m () glutSetWindowData v1 = liftIO $ dyn_glutSetWindowData ptr_glutSetWindowData v1 foreign import CALLCONV "dynamic" dyn_glutSetWindowData :: FunPtr (Ptr a -> IO ()) -> Ptr a -> IO () {-# NOINLINE ptr_glutSetWindowData #-} ptr_glutSetWindowData :: FunPtr a ptr_glutSetWindowData = unsafePerformIO $ getAPIEntry "glutSetWindowData" -- glutSetWindowTitle ---------------------------------------------------------- glutSetWindowTitle :: MonadIO m => Ptr CChar -> m () glutSetWindowTitle v1 = liftIO $ dyn_glutSetWindowTitle ptr_glutSetWindowTitle v1 foreign import CALLCONV "dynamic" dyn_glutSetWindowTitle :: FunPtr (Ptr CChar -> IO ()) -> Ptr CChar -> IO () {-# NOINLINE ptr_glutSetWindowTitle #-} ptr_glutSetWindowTitle :: FunPtr a ptr_glutSetWindowTitle = unsafePerformIO $ getAPIEntry "glutSetWindowTitle" -- glutSetupVideoResizing ------------------------------------------------------ glutSetupVideoResizing :: MonadIO m => m () glutSetupVideoResizing = liftIO $ dyn_glutSetupVideoResizing ptr_glutSetupVideoResizing foreign import CALLCONV "dynamic" dyn_glutSetupVideoResizing :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutSetupVideoResizing #-} ptr_glutSetupVideoResizing :: FunPtr a ptr_glutSetupVideoResizing = unsafePerformIO $ getAPIEntry "glutSetupVideoResizing" -- glutShowOverlay ------------------------------------------------------------- glutShowOverlay :: MonadIO m => m () glutShowOverlay = liftIO $ dyn_glutShowOverlay ptr_glutShowOverlay foreign import CALLCONV "dynamic" dyn_glutShowOverlay :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutShowOverlay #-} ptr_glutShowOverlay :: FunPtr a ptr_glutShowOverlay = unsafePerformIO $ getAPIEntry "glutShowOverlay" -- glutShowWindow -------------------------------------------------------------- glutShowWindow :: MonadIO m => m () glutShowWindow = liftIO $ dyn_glutShowWindow ptr_glutShowWindow foreign import CALLCONV "dynamic" dyn_glutShowWindow :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutShowWindow #-} ptr_glutShowWindow :: FunPtr a ptr_glutShowWindow = unsafePerformIO $ getAPIEntry "glutShowWindow" -- glutSolidCone --------------------------------------------------------------- glutSolidCone :: MonadIO m => GLdouble -> GLdouble -> GLint -> GLint -> m () glutSolidCone v1 v2 v3 v4 = liftIO $ dyn_glutSolidCone ptr_glutSolidCone v1 v2 v3 v4 foreign import CALLCONV "dynamic" dyn_glutSolidCone :: FunPtr (GLdouble -> GLdouble -> GLint -> GLint -> IO ()) -> GLdouble -> GLdouble -> GLint -> GLint -> IO () {-# NOINLINE ptr_glutSolidCone #-} ptr_glutSolidCone :: FunPtr a ptr_glutSolidCone = unsafePerformIO $ getAPIEntry "glutSolidCone" -- glutSolidCube --------------------------------------------------------------- glutSolidCube :: MonadIO m => GLdouble -> m () glutSolidCube v1 = liftIO $ dyn_glutSolidCube ptr_glutSolidCube v1 foreign import CALLCONV "dynamic" dyn_glutSolidCube :: FunPtr (GLdouble -> IO ()) -> GLdouble -> IO () {-# NOINLINE ptr_glutSolidCube #-} ptr_glutSolidCube :: FunPtr a ptr_glutSolidCube = unsafePerformIO $ getAPIEntry "glutSolidCube" -- glutSolidCylinder ----------------------------------------------------------- glutSolidCylinder :: MonadIO m => GLdouble -> GLdouble -> GLint -> GLint -> m () glutSolidCylinder v1 v2 v3 v4 = liftIO $ dyn_glutSolidCylinder ptr_glutSolidCylinder v1 v2 v3 v4 foreign import CALLCONV "dynamic" dyn_glutSolidCylinder :: FunPtr (GLdouble -> GLdouble -> GLint -> GLint -> IO ()) -> GLdouble -> GLdouble -> GLint -> GLint -> IO () {-# NOINLINE ptr_glutSolidCylinder #-} ptr_glutSolidCylinder :: FunPtr a ptr_glutSolidCylinder = unsafePerformIO $ getAPIEntry "glutSolidCylinder" -- glutSolidDodecahedron ------------------------------------------------------- glutSolidDodecahedron :: MonadIO m => m () glutSolidDodecahedron = liftIO $ dyn_glutSolidDodecahedron ptr_glutSolidDodecahedron foreign import CALLCONV "dynamic" dyn_glutSolidDodecahedron :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutSolidDodecahedron #-} ptr_glutSolidDodecahedron :: FunPtr a ptr_glutSolidDodecahedron = unsafePerformIO $ getAPIEntry "glutSolidDodecahedron" -- glutSolidIcosahedron -------------------------------------------------------- glutSolidIcosahedron :: MonadIO m => m () glutSolidIcosahedron = liftIO $ dyn_glutSolidIcosahedron ptr_glutSolidIcosahedron foreign import CALLCONV "dynamic" dyn_glutSolidIcosahedron :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutSolidIcosahedron #-} ptr_glutSolidIcosahedron :: FunPtr a ptr_glutSolidIcosahedron = unsafePerformIO $ getAPIEntry "glutSolidIcosahedron" -- glutSolidOctahedron --------------------------------------------------------- glutSolidOctahedron :: MonadIO m => m () glutSolidOctahedron = liftIO $ dyn_glutSolidOctahedron ptr_glutSolidOctahedron foreign import CALLCONV "dynamic" dyn_glutSolidOctahedron :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutSolidOctahedron #-} ptr_glutSolidOctahedron :: FunPtr a ptr_glutSolidOctahedron = unsafePerformIO $ getAPIEntry "glutSolidOctahedron" -- glutSolidRhombicDodecahedron ------------------------------------------------ glutSolidRhombicDodecahedron :: MonadIO m => m () glutSolidRhombicDodecahedron = liftIO $ dyn_glutSolidRhombicDodecahedron ptr_glutSolidRhombicDodecahedron foreign import CALLCONV "dynamic" dyn_glutSolidRhombicDodecahedron :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutSolidRhombicDodecahedron #-} ptr_glutSolidRhombicDodecahedron :: FunPtr a ptr_glutSolidRhombicDodecahedron = unsafePerformIO $ getAPIEntry "glutSolidRhombicDodecahedron" -- glutSolidSierpinskiSponge --------------------------------------------------- glutSolidSierpinskiSponge :: MonadIO m => CInt -> Ptr GLdouble -> GLdouble -> m () glutSolidSierpinskiSponge v1 v2 v3 = liftIO $ dyn_glutSolidSierpinskiSponge ptr_glutSolidSierpinskiSponge v1 v2 v3 foreign import CALLCONV "dynamic" dyn_glutSolidSierpinskiSponge :: FunPtr (CInt -> Ptr GLdouble -> GLdouble -> IO ()) -> CInt -> Ptr GLdouble -> GLdouble -> IO () {-# NOINLINE ptr_glutSolidSierpinskiSponge #-} ptr_glutSolidSierpinskiSponge :: FunPtr a ptr_glutSolidSierpinskiSponge = unsafePerformIO $ getAPIEntry "glutSolidSierpinskiSponge" -- glutSolidSphere ------------------------------------------------------------- glutSolidSphere :: MonadIO m => GLdouble -> GLint -> GLint -> m () glutSolidSphere v1 v2 v3 = liftIO $ dyn_glutSolidSphere ptr_glutSolidSphere v1 v2 v3 foreign import CALLCONV "dynamic" dyn_glutSolidSphere :: FunPtr (GLdouble -> GLint -> GLint -> IO ()) -> GLdouble -> GLint -> GLint -> IO () {-# NOINLINE ptr_glutSolidSphere #-} ptr_glutSolidSphere :: FunPtr a ptr_glutSolidSphere = unsafePerformIO $ getAPIEntry "glutSolidSphere" -- glutSolidTeacup ------------------------------------------------------------- glutSolidTeacup :: MonadIO m => GLdouble -> m () glutSolidTeacup v1 = liftIO $ dyn_glutSolidTeacup ptr_glutSolidTeacup v1 foreign import CALLCONV "dynamic" dyn_glutSolidTeacup :: FunPtr (GLdouble -> IO ()) -> GLdouble -> IO () {-# NOINLINE ptr_glutSolidTeacup #-} ptr_glutSolidTeacup :: FunPtr a ptr_glutSolidTeacup = unsafePerformIO $ getAPIEntry "glutSolidTeacup" -- glutSolidTeapot ------------------------------------------------------------- glutSolidTeapot :: MonadIO m => GLdouble -> m () glutSolidTeapot v1 = liftIO $ dyn_glutSolidTeapot ptr_glutSolidTeapot v1 foreign import CALLCONV "dynamic" dyn_glutSolidTeapot :: FunPtr (GLdouble -> IO ()) -> GLdouble -> IO () {-# NOINLINE ptr_glutSolidTeapot #-} ptr_glutSolidTeapot :: FunPtr a ptr_glutSolidTeapot = unsafePerformIO $ getAPIEntry "glutSolidTeapot" -- glutSolidTeaspoon ----------------------------------------------------------- glutSolidTeaspoon :: MonadIO m => GLdouble -> m () glutSolidTeaspoon v1 = liftIO $ dyn_glutSolidTeaspoon ptr_glutSolidTeaspoon v1 foreign import CALLCONV "dynamic" dyn_glutSolidTeaspoon :: FunPtr (GLdouble -> IO ()) -> GLdouble -> IO () {-# NOINLINE ptr_glutSolidTeaspoon #-} ptr_glutSolidTeaspoon :: FunPtr a ptr_glutSolidTeaspoon = unsafePerformIO $ getAPIEntry "glutSolidTeaspoon" -- glutSolidTetrahedron -------------------------------------------------------- glutSolidTetrahedron :: MonadIO m => m () glutSolidTetrahedron = liftIO $ dyn_glutSolidTetrahedron ptr_glutSolidTetrahedron foreign import CALLCONV "dynamic" dyn_glutSolidTetrahedron :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutSolidTetrahedron #-} ptr_glutSolidTetrahedron :: FunPtr a ptr_glutSolidTetrahedron = unsafePerformIO $ getAPIEntry "glutSolidTetrahedron" -- glutSolidTorus -------------------------------------------------------------- glutSolidTorus :: MonadIO m => GLdouble -> GLdouble -> GLint -> GLint -> m () glutSolidTorus v1 v2 v3 v4 = liftIO $ dyn_glutSolidTorus ptr_glutSolidTorus v1 v2 v3 v4 foreign import CALLCONV "dynamic" dyn_glutSolidTorus :: FunPtr (GLdouble -> GLdouble -> GLint -> GLint -> IO ()) -> GLdouble -> GLdouble -> GLint -> GLint -> IO () {-# NOINLINE ptr_glutSolidTorus #-} ptr_glutSolidTorus :: FunPtr a ptr_glutSolidTorus = unsafePerformIO $ getAPIEntry "glutSolidTorus" -- glutSpaceballButtonFunc ----------------------------------------------------- glutSpaceballButtonFunc :: MonadIO m => FunPtr SpaceballButtonFunc -> m () glutSpaceballButtonFunc v1 = liftIO $ dyn_glutSpaceballButtonFunc ptr_glutSpaceballButtonFunc v1 foreign import CALLCONV "dynamic" dyn_glutSpaceballButtonFunc :: FunPtr (FunPtr SpaceballButtonFunc -> IO ()) -> FunPtr SpaceballButtonFunc -> IO () {-# NOINLINE ptr_glutSpaceballButtonFunc #-} ptr_glutSpaceballButtonFunc :: FunPtr a ptr_glutSpaceballButtonFunc = unsafePerformIO $ getAPIEntry "glutSpaceballButtonFunc" -- glutSpaceballMotionFunc ----------------------------------------------------- glutSpaceballMotionFunc :: MonadIO m => FunPtr SpaceballMotionFunc -> m () glutSpaceballMotionFunc v1 = liftIO $ dyn_glutSpaceballMotionFunc ptr_glutSpaceballMotionFunc v1 foreign import CALLCONV "dynamic" dyn_glutSpaceballMotionFunc :: FunPtr (FunPtr SpaceballMotionFunc -> IO ()) -> FunPtr SpaceballMotionFunc -> IO () {-# NOINLINE ptr_glutSpaceballMotionFunc #-} ptr_glutSpaceballMotionFunc :: FunPtr a ptr_glutSpaceballMotionFunc = unsafePerformIO $ getAPIEntry "glutSpaceballMotionFunc" -- glutSpaceballRotateFunc ----------------------------------------------------- glutSpaceballRotateFunc :: MonadIO m => FunPtr SpaceballRotateFunc -> m () glutSpaceballRotateFunc v1 = liftIO $ dyn_glutSpaceballRotateFunc ptr_glutSpaceballRotateFunc v1 foreign import CALLCONV "dynamic" dyn_glutSpaceballRotateFunc :: FunPtr (FunPtr SpaceballRotateFunc -> IO ()) -> FunPtr SpaceballRotateFunc -> IO () {-# NOINLINE ptr_glutSpaceballRotateFunc #-} ptr_glutSpaceballRotateFunc :: FunPtr a ptr_glutSpaceballRotateFunc = unsafePerformIO $ getAPIEntry "glutSpaceballRotateFunc" -- glutSpecialFunc ------------------------------------------------------------- glutSpecialFunc :: MonadIO m => FunPtr SpecialFunc -> m () glutSpecialFunc v1 = liftIO $ dyn_glutSpecialFunc ptr_glutSpecialFunc v1 foreign import CALLCONV "dynamic" dyn_glutSpecialFunc :: FunPtr (FunPtr SpecialFunc -> IO ()) -> FunPtr SpecialFunc -> IO () {-# NOINLINE ptr_glutSpecialFunc #-} ptr_glutSpecialFunc :: FunPtr a ptr_glutSpecialFunc = unsafePerformIO $ getAPIEntry "glutSpecialFunc" -- glutSpecialUpFunc ----------------------------------------------------------- glutSpecialUpFunc :: MonadIO m => FunPtr SpecialUpFunc -> m () glutSpecialUpFunc v1 = liftIO $ dyn_glutSpecialUpFunc ptr_glutSpecialUpFunc v1 foreign import CALLCONV "dynamic" dyn_glutSpecialUpFunc :: FunPtr (FunPtr SpecialUpFunc -> IO ()) -> FunPtr SpecialUpFunc -> IO () {-# NOINLINE ptr_glutSpecialUpFunc #-} ptr_glutSpecialUpFunc :: FunPtr a ptr_glutSpecialUpFunc = unsafePerformIO $ getAPIEntry "glutSpecialUpFunc" -- glutStopVideoResizing ------------------------------------------------------- glutStopVideoResizing :: MonadIO m => m () glutStopVideoResizing = liftIO $ dyn_glutStopVideoResizing ptr_glutStopVideoResizing foreign import CALLCONV "dynamic" dyn_glutStopVideoResizing :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutStopVideoResizing #-} ptr_glutStopVideoResizing :: FunPtr a ptr_glutStopVideoResizing = unsafePerformIO $ getAPIEntry "glutStopVideoResizing" -- glutStrokeCharacter --------------------------------------------------------- glutStrokeCharacter :: MonadIO m => Ptr a -> CInt -> m () glutStrokeCharacter v1 v2 = liftIO $ dyn_glutStrokeCharacter ptr_glutStrokeCharacter v1 v2 foreign import CALLCONV "dynamic" dyn_glutStrokeCharacter :: FunPtr (Ptr a -> CInt -> IO ()) -> Ptr a -> CInt -> IO () {-# NOINLINE ptr_glutStrokeCharacter #-} ptr_glutStrokeCharacter :: FunPtr a ptr_glutStrokeCharacter = unsafePerformIO $ getAPIEntry "glutStrokeCharacter" -- glutStrokeHeight ------------------------------------------------------------ glutStrokeHeight :: MonadIO m => Ptr a -> m GLfloat glutStrokeHeight v1 = liftIO $ dyn_glutStrokeHeight ptr_glutStrokeHeight v1 foreign import CALLCONV "dynamic" dyn_glutStrokeHeight :: FunPtr (Ptr a -> IO GLfloat) -> Ptr a -> IO GLfloat {-# NOINLINE ptr_glutStrokeHeight #-} ptr_glutStrokeHeight :: FunPtr a ptr_glutStrokeHeight = unsafePerformIO $ getAPIEntry "glutStrokeHeight" -- glutStrokeLength ------------------------------------------------------------ glutStrokeLength :: MonadIO m => Ptr a -> Ptr CUChar -> m CInt glutStrokeLength v1 v2 = liftIO $ dyn_glutStrokeLength ptr_glutStrokeLength v1 v2 foreign import CALLCONV "dynamic" dyn_glutStrokeLength :: FunPtr (Ptr a -> Ptr CUChar -> IO CInt) -> Ptr a -> Ptr CUChar -> IO CInt {-# NOINLINE ptr_glutStrokeLength #-} ptr_glutStrokeLength :: FunPtr a ptr_glutStrokeLength = unsafePerformIO $ getAPIEntry "glutStrokeLength" -- glutStrokeString ------------------------------------------------------------ glutStrokeString :: MonadIO m => Ptr a -> Ptr CUChar -> m () glutStrokeString v1 v2 = liftIO $ dyn_glutStrokeString ptr_glutStrokeString v1 v2 foreign import CALLCONV "dynamic" dyn_glutStrokeString :: FunPtr (Ptr a -> Ptr CUChar -> IO ()) -> Ptr a -> Ptr CUChar -> IO () {-# NOINLINE ptr_glutStrokeString #-} ptr_glutStrokeString :: FunPtr a ptr_glutStrokeString = unsafePerformIO $ getAPIEntry "glutStrokeString" -- glutStrokeWidth ------------------------------------------------------------- glutStrokeWidth :: MonadIO m => Ptr a -> CInt -> m CInt glutStrokeWidth v1 v2 = liftIO $ dyn_glutStrokeWidth ptr_glutStrokeWidth v1 v2 foreign import CALLCONV "dynamic" dyn_glutStrokeWidth :: FunPtr (Ptr a -> CInt -> IO CInt) -> Ptr a -> CInt -> IO CInt {-# NOINLINE ptr_glutStrokeWidth #-} ptr_glutStrokeWidth :: FunPtr a ptr_glutStrokeWidth = unsafePerformIO $ getAPIEntry "glutStrokeWidth" -- glutSwapBuffers ------------------------------------------------------------- glutSwapBuffers :: MonadIO m => m () glutSwapBuffers = liftIO $ dyn_glutSwapBuffers ptr_glutSwapBuffers foreign import CALLCONV "dynamic" dyn_glutSwapBuffers :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutSwapBuffers #-} ptr_glutSwapBuffers :: FunPtr a ptr_glutSwapBuffers = unsafePerformIO $ getAPIEntry "glutSwapBuffers" -- glutTabletButtonFunc -------------------------------------------------------- glutTabletButtonFunc :: MonadIO m => FunPtr TabletButtonFunc -> m () glutTabletButtonFunc v1 = liftIO $ dyn_glutTabletButtonFunc ptr_glutTabletButtonFunc v1 foreign import CALLCONV "dynamic" dyn_glutTabletButtonFunc :: FunPtr (FunPtr TabletButtonFunc -> IO ()) -> FunPtr TabletButtonFunc -> IO () {-# NOINLINE ptr_glutTabletButtonFunc #-} ptr_glutTabletButtonFunc :: FunPtr a ptr_glutTabletButtonFunc = unsafePerformIO $ getAPIEntry "glutTabletButtonFunc" -- glutTabletMotionFunc -------------------------------------------------------- glutTabletMotionFunc :: MonadIO m => FunPtr TabletMotionFunc -> m () glutTabletMotionFunc v1 = liftIO $ dyn_glutTabletMotionFunc ptr_glutTabletMotionFunc v1 foreign import CALLCONV "dynamic" dyn_glutTabletMotionFunc :: FunPtr (FunPtr TabletMotionFunc -> IO ()) -> FunPtr TabletMotionFunc -> IO () {-# NOINLINE ptr_glutTabletMotionFunc #-} ptr_glutTabletMotionFunc :: FunPtr a ptr_glutTabletMotionFunc = unsafePerformIO $ getAPIEntry "glutTabletMotionFunc" -- glutTimerFunc --------------------------------------------------------------- glutTimerFunc :: MonadIO m => CUInt -> FunPtr TimerFunc -> CInt -> m () glutTimerFunc v1 v2 v3 = liftIO $ dyn_glutTimerFunc ptr_glutTimerFunc v1 v2 v3 foreign import CALLCONV "dynamic" dyn_glutTimerFunc :: FunPtr (CUInt -> FunPtr TimerFunc -> CInt -> IO ()) -> CUInt -> FunPtr TimerFunc -> CInt -> IO () {-# NOINLINE ptr_glutTimerFunc #-} ptr_glutTimerFunc :: FunPtr a ptr_glutTimerFunc = unsafePerformIO $ getAPIEntry "glutTimerFunc" -- glutUseLayer ---------------------------------------------------------------- glutUseLayer :: MonadIO m => GLenum -> m () glutUseLayer v1 = liftIO $ dyn_glutUseLayer ptr_glutUseLayer v1 foreign import CALLCONV "dynamic" dyn_glutUseLayer :: FunPtr (GLenum -> IO ()) -> GLenum -> IO () {-# NOINLINE ptr_glutUseLayer #-} ptr_glutUseLayer :: FunPtr a ptr_glutUseLayer = unsafePerformIO $ getAPIEntry "glutUseLayer" -- glutVideoPan ---------------------------------------------------------------- glutVideoPan :: MonadIO m => CInt -> CInt -> CInt -> CInt -> m () glutVideoPan v1 v2 v3 v4 = liftIO $ dyn_glutVideoPan ptr_glutVideoPan v1 v2 v3 v4 foreign import CALLCONV "dynamic" dyn_glutVideoPan :: FunPtr (CInt -> CInt -> CInt -> CInt -> IO ()) -> CInt -> CInt -> CInt -> CInt -> IO () {-# NOINLINE ptr_glutVideoPan #-} ptr_glutVideoPan :: FunPtr a ptr_glutVideoPan = unsafePerformIO $ getAPIEntry "glutVideoPan" -- glutVideoResize ------------------------------------------------------------- glutVideoResize :: MonadIO m => CInt -> CInt -> CInt -> CInt -> m () glutVideoResize v1 v2 v3 v4 = liftIO $ dyn_glutVideoResize ptr_glutVideoResize v1 v2 v3 v4 foreign import CALLCONV "dynamic" dyn_glutVideoResize :: FunPtr (CInt -> CInt -> CInt -> CInt -> IO ()) -> CInt -> CInt -> CInt -> CInt -> IO () {-# NOINLINE ptr_glutVideoResize #-} ptr_glutVideoResize :: FunPtr a ptr_glutVideoResize = unsafePerformIO $ getAPIEntry "glutVideoResize" -- glutVideoResizeGet ---------------------------------------------------------- glutVideoResizeGet :: MonadIO m => GLenum -> m CInt glutVideoResizeGet v1 = liftIO $ dyn_glutVideoResizeGet ptr_glutVideoResizeGet v1 foreign import CALLCONV "dynamic" dyn_glutVideoResizeGet :: FunPtr (GLenum -> IO CInt) -> GLenum -> IO CInt {-# NOINLINE ptr_glutVideoResizeGet #-} ptr_glutVideoResizeGet :: FunPtr a ptr_glutVideoResizeGet = unsafePerformIO $ getAPIEntry "glutVideoResizeGet" -- glutVisibilityFunc ---------------------------------------------------------- glutVisibilityFunc :: MonadIO m => FunPtr VisibilityFunc -> m () glutVisibilityFunc v1 = liftIO $ dyn_glutVisibilityFunc ptr_glutVisibilityFunc v1 foreign import CALLCONV "dynamic" dyn_glutVisibilityFunc :: FunPtr (FunPtr VisibilityFunc -> IO ()) -> FunPtr VisibilityFunc -> IO () {-# NOINLINE ptr_glutVisibilityFunc #-} ptr_glutVisibilityFunc :: FunPtr a ptr_glutVisibilityFunc = unsafePerformIO $ getAPIEntry "glutVisibilityFunc" -- glutWMCloseFunc ------------------------------------------------------------- glutWMCloseFunc :: MonadIO m => FunPtr WMCloseFunc -> m () glutWMCloseFunc v1 = liftIO $ dyn_glutWMCloseFunc ptr_glutWMCloseFunc v1 foreign import CALLCONV "dynamic" dyn_glutWMCloseFunc :: FunPtr (FunPtr WMCloseFunc -> IO ()) -> FunPtr WMCloseFunc -> IO () {-# NOINLINE ptr_glutWMCloseFunc #-} ptr_glutWMCloseFunc :: FunPtr a ptr_glutWMCloseFunc = unsafePerformIO $ getAPIEntry "glutWMCloseFunc" -- glutWarpPointer ------------------------------------------------------------- glutWarpPointer :: MonadIO m => CInt -> CInt -> m () glutWarpPointer v1 v2 = liftIO $ dyn_glutWarpPointer ptr_glutWarpPointer v1 v2 foreign import CALLCONV "dynamic" dyn_glutWarpPointer :: FunPtr (CInt -> CInt -> IO ()) -> CInt -> CInt -> IO () {-# NOINLINE ptr_glutWarpPointer #-} ptr_glutWarpPointer :: FunPtr a ptr_glutWarpPointer = unsafePerformIO $ getAPIEntry "glutWarpPointer" -- glutWindowStatusFunc -------------------------------------------------------- glutWindowStatusFunc :: MonadIO m => FunPtr WindowStatusFunc -> m () glutWindowStatusFunc v1 = liftIO $ dyn_glutWindowStatusFunc ptr_glutWindowStatusFunc v1 foreign import CALLCONV "dynamic" dyn_glutWindowStatusFunc :: FunPtr (FunPtr WindowStatusFunc -> IO ()) -> FunPtr WindowStatusFunc -> IO () {-# NOINLINE ptr_glutWindowStatusFunc #-} ptr_glutWindowStatusFunc :: FunPtr a ptr_glutWindowStatusFunc = unsafePerformIO $ getAPIEntry "glutWindowStatusFunc" -- glutWireCone ---------------------------------------------------------------- glutWireCone :: MonadIO m => GLdouble -> GLdouble -> GLint -> GLint -> m () glutWireCone v1 v2 v3 v4 = liftIO $ dyn_glutWireCone ptr_glutWireCone v1 v2 v3 v4 foreign import CALLCONV "dynamic" dyn_glutWireCone :: FunPtr (GLdouble -> GLdouble -> GLint -> GLint -> IO ()) -> GLdouble -> GLdouble -> GLint -> GLint -> IO () {-# NOINLINE ptr_glutWireCone #-} ptr_glutWireCone :: FunPtr a ptr_glutWireCone = unsafePerformIO $ getAPIEntry "glutWireCone" -- glutWireCube ---------------------------------------------------------------- glutWireCube :: MonadIO m => GLdouble -> m () glutWireCube v1 = liftIO $ dyn_glutWireCube ptr_glutWireCube v1 foreign import CALLCONV "dynamic" dyn_glutWireCube :: FunPtr (GLdouble -> IO ()) -> GLdouble -> IO () {-# NOINLINE ptr_glutWireCube #-} ptr_glutWireCube :: FunPtr a ptr_glutWireCube = unsafePerformIO $ getAPIEntry "glutWireCube" -- glutWireCylinder ------------------------------------------------------------ glutWireCylinder :: MonadIO m => GLdouble -> GLdouble -> GLint -> GLint -> m () glutWireCylinder v1 v2 v3 v4 = liftIO $ dyn_glutWireCylinder ptr_glutWireCylinder v1 v2 v3 v4 foreign import CALLCONV "dynamic" dyn_glutWireCylinder :: FunPtr (GLdouble -> GLdouble -> GLint -> GLint -> IO ()) -> GLdouble -> GLdouble -> GLint -> GLint -> IO () {-# NOINLINE ptr_glutWireCylinder #-} ptr_glutWireCylinder :: FunPtr a ptr_glutWireCylinder = unsafePerformIO $ getAPIEntry "glutWireCylinder" -- glutWireDodecahedron -------------------------------------------------------- glutWireDodecahedron :: MonadIO m => m () glutWireDodecahedron = liftIO $ dyn_glutWireDodecahedron ptr_glutWireDodecahedron foreign import CALLCONV "dynamic" dyn_glutWireDodecahedron :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutWireDodecahedron #-} ptr_glutWireDodecahedron :: FunPtr a ptr_glutWireDodecahedron = unsafePerformIO $ getAPIEntry "glutWireDodecahedron" -- glutWireIcosahedron --------------------------------------------------------- glutWireIcosahedron :: MonadIO m => m () glutWireIcosahedron = liftIO $ dyn_glutWireIcosahedron ptr_glutWireIcosahedron foreign import CALLCONV "dynamic" dyn_glutWireIcosahedron :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutWireIcosahedron #-} ptr_glutWireIcosahedron :: FunPtr a ptr_glutWireIcosahedron = unsafePerformIO $ getAPIEntry "glutWireIcosahedron" -- glutWireOctahedron ---------------------------------------------------------- glutWireOctahedron :: MonadIO m => m () glutWireOctahedron = liftIO $ dyn_glutWireOctahedron ptr_glutWireOctahedron foreign import CALLCONV "dynamic" dyn_glutWireOctahedron :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutWireOctahedron #-} ptr_glutWireOctahedron :: FunPtr a ptr_glutWireOctahedron = unsafePerformIO $ getAPIEntry "glutWireOctahedron" -- glutWireRhombicDodecahedron ------------------------------------------------- glutWireRhombicDodecahedron :: MonadIO m => m () glutWireRhombicDodecahedron = liftIO $ dyn_glutWireRhombicDodecahedron ptr_glutWireRhombicDodecahedron foreign import CALLCONV "dynamic" dyn_glutWireRhombicDodecahedron :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutWireRhombicDodecahedron #-} ptr_glutWireRhombicDodecahedron :: FunPtr a ptr_glutWireRhombicDodecahedron = unsafePerformIO $ getAPIEntry "glutWireRhombicDodecahedron" -- glutWireSierpinskiSponge ---------------------------------------------------- glutWireSierpinskiSponge :: MonadIO m => CInt -> Ptr GLdouble -> GLdouble -> m () glutWireSierpinskiSponge v1 v2 v3 = liftIO $ dyn_glutWireSierpinskiSponge ptr_glutWireSierpinskiSponge v1 v2 v3 foreign import CALLCONV "dynamic" dyn_glutWireSierpinskiSponge :: FunPtr (CInt -> Ptr GLdouble -> GLdouble -> IO ()) -> CInt -> Ptr GLdouble -> GLdouble -> IO () {-# NOINLINE ptr_glutWireSierpinskiSponge #-} ptr_glutWireSierpinskiSponge :: FunPtr a ptr_glutWireSierpinskiSponge = unsafePerformIO $ getAPIEntry "glutWireSierpinskiSponge" -- glutWireSphere -------------------------------------------------------------- glutWireSphere :: MonadIO m => GLdouble -> GLint -> GLint -> m () glutWireSphere v1 v2 v3 = liftIO $ dyn_glutWireSphere ptr_glutWireSphere v1 v2 v3 foreign import CALLCONV "dynamic" dyn_glutWireSphere :: FunPtr (GLdouble -> GLint -> GLint -> IO ()) -> GLdouble -> GLint -> GLint -> IO () {-# NOINLINE ptr_glutWireSphere #-} ptr_glutWireSphere :: FunPtr a ptr_glutWireSphere = unsafePerformIO $ getAPIEntry "glutWireSphere" -- glutWireTeacup -------------------------------------------------------------- glutWireTeacup :: MonadIO m => GLdouble -> m () glutWireTeacup v1 = liftIO $ dyn_glutWireTeacup ptr_glutWireTeacup v1 foreign import CALLCONV "dynamic" dyn_glutWireTeacup :: FunPtr (GLdouble -> IO ()) -> GLdouble -> IO () {-# NOINLINE ptr_glutWireTeacup #-} ptr_glutWireTeacup :: FunPtr a ptr_glutWireTeacup = unsafePerformIO $ getAPIEntry "glutWireTeacup" -- glutWireTeapot -------------------------------------------------------------- glutWireTeapot :: MonadIO m => GLdouble -> m () glutWireTeapot v1 = liftIO $ dyn_glutWireTeapot ptr_glutWireTeapot v1 foreign import CALLCONV "dynamic" dyn_glutWireTeapot :: FunPtr (GLdouble -> IO ()) -> GLdouble -> IO () {-# NOINLINE ptr_glutWireTeapot #-} ptr_glutWireTeapot :: FunPtr a ptr_glutWireTeapot = unsafePerformIO $ getAPIEntry "glutWireTeapot" -- glutWireTeaspoon ------------------------------------------------------------ glutWireTeaspoon :: MonadIO m => GLdouble -> m () glutWireTeaspoon v1 = liftIO $ dyn_glutWireTeaspoon ptr_glutWireTeaspoon v1 foreign import CALLCONV "dynamic" dyn_glutWireTeaspoon :: FunPtr (GLdouble -> IO ()) -> GLdouble -> IO () {-# NOINLINE ptr_glutWireTeaspoon #-} ptr_glutWireTeaspoon :: FunPtr a ptr_glutWireTeaspoon = unsafePerformIO $ getAPIEntry "glutWireTeaspoon" -- glutWireTetrahedron --------------------------------------------------------- glutWireTetrahedron :: MonadIO m => m () glutWireTetrahedron = liftIO $ dyn_glutWireTetrahedron ptr_glutWireTetrahedron foreign import CALLCONV "dynamic" dyn_glutWireTetrahedron :: FunPtr (IO ()) -> IO () {-# NOINLINE ptr_glutWireTetrahedron #-} ptr_glutWireTetrahedron :: FunPtr a ptr_glutWireTetrahedron = unsafePerformIO $ getAPIEntry "glutWireTetrahedron" -- glutWireTorus --------------------------------------------------------------- glutWireTorus :: MonadIO m => GLdouble -> GLdouble -> GLint -> GLint -> m () glutWireTorus v1 v2 v3 v4 = liftIO $ dyn_glutWireTorus ptr_glutWireTorus v1 v2 v3 v4 foreign import CALLCONV "dynamic" dyn_glutWireTorus :: FunPtr (GLdouble -> GLdouble -> GLint -> GLint -> IO ()) -> GLdouble -> GLdouble -> GLint -> GLint -> IO () {-# NOINLINE ptr_glutWireTorus #-} ptr_glutWireTorus :: FunPtr a ptr_glutWireTorus = unsafePerformIO $ getAPIEntry "glutWireTorus" GLUT-2.7.0.16/src/Graphics/UI/GLUT/Raw/Tokens.hs0000644000000000000000000003044313255126367016673 0ustar0000000000000000{-# OPTIONS_HADDOCK hide #-} ----------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Raw.Tokens -- Copyright : (c) Sven Panne 2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- All tokens from GLUT and freeglut. -- ----------------------------------------------------------------------------- module Graphics.UI.GLUT.Raw.Tokens where import Foreign.C.Types ( CInt, CUInt ) import Graphics.Rendering.OpenGL ( GLenum ) glut_ACCUM :: CUInt glut_ACCUM = 0x0004 glut_ACTION_CONTINUE_EXECUTION :: CInt glut_ACTION_CONTINUE_EXECUTION = 2 glut_ACTION_EXIT :: CInt glut_ACTION_EXIT = 0 glut_ACTION_GLUTMAINLOOP_RETURNS :: CInt glut_ACTION_GLUTMAINLOOP_RETURNS = 1 glut_ACTION_ON_WINDOW_CLOSE :: GLenum glut_ACTION_ON_WINDOW_CLOSE = 0x01F9 glut_ACTIVE_ALT :: CInt glut_ACTIVE_ALT = 0x0004 glut_ACTIVE_CTRL :: CInt glut_ACTIVE_CTRL = 0x0002 glut_ACTIVE_SHIFT :: CInt glut_ACTIVE_SHIFT = 0x0001 glut_ALLOW_DIRECT_CONTEXT :: CInt glut_ALLOW_DIRECT_CONTEXT = 1 glut_ALPHA :: CUInt glut_ALPHA = 0x0008 glut_APPSTATUS_PAUSE :: CInt glut_APPSTATUS_PAUSE = 0x0001 glut_APPSTATUS_RESUME :: CInt glut_APPSTATUS_RESUME = 0x0002 glut_AUX :: GLenum glut_AUX = 0x1000 glut_AUX1 :: CUInt glut_AUX1 = 0x1000 glut_AUX2 :: CUInt glut_AUX2 = 0x2000 glut_AUX3 :: CUInt glut_AUX3 = 0x4000 glut_AUX4 :: CUInt glut_AUX4 = 0x8000 glut_BLUE :: CInt glut_BLUE = 0x0002 glut_BORDERLESS :: CUInt glut_BORDERLESS = 0x0800 glut_CAPTIONLESS :: CUInt glut_CAPTIONLESS = 0x0400 glut_CORE_PROFILE :: CInt glut_CORE_PROFILE = 0x0001 glut_COMPATIBILITY_PROFILE :: CInt glut_COMPATIBILITY_PROFILE = 0x0002 glut_CREATE_NEW_CONTEXT :: CInt glut_CREATE_NEW_CONTEXT = 0 glut_CURSOR_BOTTOM_LEFT_CORNER :: CInt glut_CURSOR_BOTTOM_LEFT_CORNER = 0x0013 glut_CURSOR_BOTTOM_RIGHT_CORNER :: CInt glut_CURSOR_BOTTOM_RIGHT_CORNER = 0x0012 glut_CURSOR_BOTTOM_SIDE :: CInt glut_CURSOR_BOTTOM_SIDE = 0x000D glut_CURSOR_CROSSHAIR :: CInt glut_CURSOR_CROSSHAIR = 0x0009 glut_CURSOR_CYCLE :: CInt glut_CURSOR_CYCLE = 0x0005 glut_CURSOR_DESTROY :: CInt glut_CURSOR_DESTROY = 0x0003 glut_CURSOR_FULL_CROSSHAIR :: CInt glut_CURSOR_FULL_CROSSHAIR = 0x0066 glut_CURSOR_HELP :: CInt glut_CURSOR_HELP = 0x0004 glut_CURSOR_INFO :: CInt glut_CURSOR_INFO = 0x0002 glut_CURSOR_INHERIT :: CInt glut_CURSOR_INHERIT = 0x0064 glut_CURSOR_LEFT_ARROW :: CInt glut_CURSOR_LEFT_ARROW = 0x0001 glut_CURSOR_LEFT_RIGHT :: CInt glut_CURSOR_LEFT_RIGHT = 0x000B glut_CURSOR_LEFT_SIDE :: CInt glut_CURSOR_LEFT_SIDE = 0x000E glut_CURSOR_NONE :: CInt glut_CURSOR_NONE = 0x0065 glut_CURSOR_RIGHT_ARROW :: CInt glut_CURSOR_RIGHT_ARROW = 0x0000 glut_CURSOR_RIGHT_SIDE :: CInt glut_CURSOR_RIGHT_SIDE = 0x000F glut_CURSOR_SPRAY :: CInt glut_CURSOR_SPRAY = 0x0006 glut_CURSOR_TEXT :: CInt glut_CURSOR_TEXT = 0x0008 glut_CURSOR_TOP_LEFT_CORNER :: CInt glut_CURSOR_TOP_LEFT_CORNER = 0x0010 glut_CURSOR_TOP_RIGHT_CORNER :: CInt glut_CURSOR_TOP_RIGHT_CORNER = 0x0011 glut_CURSOR_TOP_SIDE :: CInt glut_CURSOR_TOP_SIDE = 0x000C glut_CURSOR_UP_DOWN :: CInt glut_CURSOR_UP_DOWN = 0x000A glut_CURSOR_WAIT :: CInt glut_CURSOR_WAIT = 0x0007 glut_DEBUG :: CInt glut_DEBUG = 0x0001 glut_DEPTH :: CUInt glut_DEPTH = 0x0010 glut_DEVICE_IGNORE_KEY_REPEAT :: GLenum glut_DEVICE_IGNORE_KEY_REPEAT = 0x0262 glut_DEVICE_KEY_REPEAT :: GLenum glut_DEVICE_KEY_REPEAT = 0x0263 glut_DIRECT_RENDERING :: GLenum glut_DIRECT_RENDERING = 0x01FE glut_DISPLAY_MODE_POSSIBLE :: GLenum glut_DISPLAY_MODE_POSSIBLE = 0x0190 glut_DOUBLE :: CUInt glut_DOUBLE = 0x0002 glut_DOWN :: CInt glut_DOWN = 0x0000 glut_ELAPSED_TIME :: GLenum glut_ELAPSED_TIME = 0x02BC glut_ENTERED :: CInt glut_ENTERED = 0x0001 glut_FORCE_DIRECT_CONTEXT :: CInt glut_FORCE_DIRECT_CONTEXT = 3 glut_FORCE_INDIRECT_CONTEXT :: CInt glut_FORCE_INDIRECT_CONTEXT = 0 glut_FORWARD_COMPATIBLE :: CInt glut_FORWARD_COMPATIBLE = 0x0002 glut_FULLY_COVERED :: CInt glut_FULLY_COVERED = 0x0003 glut_FULLY_RETAINED :: CInt glut_FULLY_RETAINED = 0x0001 glut_FULL_SCREEN :: GLenum glut_FULL_SCREEN = 0x01FF glut_GAME_MODE_ACTIVE :: GLenum glut_GAME_MODE_ACTIVE = 0x0000 glut_GAME_MODE_DISPLAY_CHANGED :: GLenum glut_GAME_MODE_DISPLAY_CHANGED = 0x0006 glut_GAME_MODE_HEIGHT :: GLenum glut_GAME_MODE_HEIGHT = 0x0003 glut_GAME_MODE_PIXEL_DEPTH :: GLenum glut_GAME_MODE_PIXEL_DEPTH = 0x0004 glut_GAME_MODE_POSSIBLE :: GLenum glut_GAME_MODE_POSSIBLE = 0x0001 glut_GAME_MODE_REFRESH_RATE :: GLenum glut_GAME_MODE_REFRESH_RATE = 0x0005 glut_GAME_MODE_WIDTH :: GLenum glut_GAME_MODE_WIDTH = 0x0002 glut_GEOMETRY_VISUALIZE_NORMALS :: GLenum glut_GEOMETRY_VISUALIZE_NORMALS = 0x0205 glut_GREEN :: CInt glut_GREEN = 0x0001 glut_HAS_DIAL_AND_BUTTON_BOX :: GLenum glut_HAS_DIAL_AND_BUTTON_BOX = 0x025B glut_HAS_JOYSTICK :: GLenum glut_HAS_JOYSTICK = 0x0264 glut_HAS_KEYBOARD :: GLenum glut_HAS_KEYBOARD = 0x0258 glut_HAS_MOUSE :: GLenum glut_HAS_MOUSE = 0x0259 glut_HAS_OVERLAY :: GLenum glut_HAS_OVERLAY = 0x0322 glut_HAS_SPACEBALL :: GLenum glut_HAS_SPACEBALL = 0x025A glut_HAS_TABLET :: GLenum glut_HAS_TABLET = 0x025C glut_HIDDEN :: CInt glut_HIDDEN = 0x0000 glut_INDEX :: CUInt glut_INDEX = 0x0001 glut_INIT_DISPLAY_MODE :: GLenum glut_INIT_DISPLAY_MODE = 0x01F8 glut_INIT_FLAGS :: GLenum glut_INIT_FLAGS = 0x0202 glut_INIT_MAJOR_VERSION :: GLenum glut_INIT_MAJOR_VERSION = 0x0200 glut_INIT_MINOR_VERSION :: GLenum glut_INIT_MINOR_VERSION = 0x0201 glut_INIT_PROFILE :: GLenum glut_INIT_PROFILE = 0x0203 glut_INIT_STATE :: GLenum glut_INIT_STATE = 0x007C glut_INIT_WINDOW_HEIGHT :: GLenum glut_INIT_WINDOW_HEIGHT = 0x01F7 glut_INIT_WINDOW_WIDTH :: GLenum glut_INIT_WINDOW_WIDTH = 0x01F6 glut_INIT_WINDOW_X :: GLenum glut_INIT_WINDOW_X = 0x01F4 glut_INIT_WINDOW_Y :: GLenum glut_INIT_WINDOW_Y = 0x01F5 glut_JOYSTICK_AXES :: GLenum glut_JOYSTICK_AXES = 0x0267 glut_JOYSTICK_BUTTONS :: GLenum glut_JOYSTICK_BUTTONS = 0x0266 glut_JOYSTICK_BUTTON_A :: CUInt glut_JOYSTICK_BUTTON_A = 0x0001 glut_JOYSTICK_BUTTON_B :: CUInt glut_JOYSTICK_BUTTON_B = 0x0002 glut_JOYSTICK_BUTTON_C :: CUInt glut_JOYSTICK_BUTTON_C = 0x0004 glut_JOYSTICK_BUTTON_D :: CUInt glut_JOYSTICK_BUTTON_D = 0x0008 glut_JOYSTICK_POLL_RATE :: GLenum glut_JOYSTICK_POLL_RATE = 0x0268 glut_KEY_ALT_L :: CInt glut_KEY_ALT_L = 0x0074 glut_KEY_ALT_R :: CInt glut_KEY_ALT_R = 0x0075 glut_KEY_BEGIN :: CInt glut_KEY_BEGIN = 0x006E glut_KEY_CTRL_L :: CInt glut_KEY_CTRL_L = 0x0072 glut_KEY_CTRL_R :: CInt glut_KEY_CTRL_R = 0x0073 glut_KEY_DELETE :: CInt glut_KEY_DELETE = 0x006F glut_KEY_DOWN :: CInt glut_KEY_DOWN = 0x0067 glut_KEY_END :: CInt glut_KEY_END = 0x006B glut_KEY_F1 :: CInt glut_KEY_F1 = 0x0001 glut_KEY_F10 :: CInt glut_KEY_F10 = 0x000A glut_KEY_F11 :: CInt glut_KEY_F11 = 0x000B glut_KEY_F12 :: CInt glut_KEY_F12 = 0x000C glut_KEY_F2 :: CInt glut_KEY_F2 = 0x0002 glut_KEY_F3 :: CInt glut_KEY_F3 = 0x0003 glut_KEY_F4 :: CInt glut_KEY_F4 = 0x0004 glut_KEY_F5 :: CInt glut_KEY_F5 = 0x0005 glut_KEY_F6 :: CInt glut_KEY_F6 = 0x0006 glut_KEY_F7 :: CInt glut_KEY_F7 = 0x0007 glut_KEY_F8 :: CInt glut_KEY_F8 = 0x0008 glut_KEY_F9 :: CInt glut_KEY_F9 = 0x0009 glut_KEY_HOME :: CInt glut_KEY_HOME = 0x006A glut_KEY_INSERT :: CInt glut_KEY_INSERT = 0x006C glut_KEY_LEFT :: CInt glut_KEY_LEFT = 0x0064 glut_KEY_NUM_LOCK :: CInt glut_KEY_NUM_LOCK = 0x006D glut_KEY_PAGE_DOWN :: CInt glut_KEY_PAGE_DOWN = 0x0069 glut_KEY_PAGE_UP :: CInt glut_KEY_PAGE_UP = 0x0068 glut_KEY_REPEAT_DEFAULT :: CInt glut_KEY_REPEAT_DEFAULT = 0x0002 glut_KEY_REPEAT_OFF :: CInt glut_KEY_REPEAT_OFF = 0x0000 glut_KEY_REPEAT_ON :: CInt glut_KEY_REPEAT_ON = 0x0001 glut_KEY_RIGHT :: CInt glut_KEY_RIGHT = 0x0066 glut_KEY_SHIFT_L :: CInt glut_KEY_SHIFT_L = 0x0070 glut_KEY_SHIFT_R :: CInt glut_KEY_SHIFT_R = 0x0071 glut_KEY_UP :: CInt glut_KEY_UP = 0x0065 glut_LAYER_IN_USE :: GLenum glut_LAYER_IN_USE = 0x0321 glut_LEFT :: CInt glut_LEFT = 0x0000 glut_LEFT_BUTTON :: CInt glut_LEFT_BUTTON = 0x0000 glut_LUMINANCE :: CUInt glut_LUMINANCE = 0x0200 glut_MENU_IN_USE :: CInt glut_MENU_IN_USE = 0x0001 glut_MENU_NOT_IN_USE :: CInt glut_MENU_NOT_IN_USE = 0x0000 glut_MENU_NUM_ITEMS :: GLenum glut_MENU_NUM_ITEMS = 0x012C glut_MIDDLE_BUTTON :: CInt glut_MIDDLE_BUTTON = 0x0001 glut_MULTISAMPLE :: CUInt glut_MULTISAMPLE = 0x0080 glut_NORMAL :: GLenum glut_NORMAL = 0x0000 glut_NORMAL_DAMAGED :: GLenum glut_NORMAL_DAMAGED = 0x0324 glut_NOT_VISIBLE :: CInt glut_NOT_VISIBLE = 0x0000 glut_NUM_BUTTON_BOX_BUTTONS :: GLenum glut_NUM_BUTTON_BOX_BUTTONS = 0x025F glut_NUM_DIALS :: GLenum glut_NUM_DIALS = 0x0260 glut_NUM_MOUSE_BUTTONS :: GLenum glut_NUM_MOUSE_BUTTONS = 0x025D glut_NUM_SPACEBALL_BUTTONS :: GLenum glut_NUM_SPACEBALL_BUTTONS = 0x025E glut_NUM_TABLET_BUTTONS :: GLenum glut_NUM_TABLET_BUTTONS = 0x0261 glut_OVERLAY :: GLenum glut_OVERLAY = 0x0001 glut_OVERLAY_DAMAGED :: GLenum glut_OVERLAY_DAMAGED = 0x0325 glut_OVERLAY_POSSIBLE :: GLenum glut_OVERLAY_POSSIBLE = 0x0320 glut_OWNS_JOYSTICK :: GLenum glut_OWNS_JOYSTICK = 0x0265 glut_PARTIALLY_RETAINED :: CInt glut_PARTIALLY_RETAINED = 0x0002 glut_RED :: CInt glut_RED = 0x0000 glut_RENDERING_CONTEXT :: GLenum glut_RENDERING_CONTEXT = 0x01FD glut_RGB :: CUInt glut_RGB = 0x0000 glut_RGBA :: CUInt glut_RGBA = 0x0000 glut_RIGHT_BUTTON :: CInt glut_RIGHT_BUTTON = 0x0002 glut_SCREEN_HEIGHT :: GLenum glut_SCREEN_HEIGHT = 0x00C9 glut_SCREEN_HEIGHT_MM :: GLenum glut_SCREEN_HEIGHT_MM = 0x00CB glut_SCREEN_WIDTH :: GLenum glut_SCREEN_WIDTH = 0x00C8 glut_SCREEN_WIDTH_MM :: GLenum glut_SCREEN_WIDTH_MM = 0x00CA glut_SINGLE :: CUInt glut_SINGLE = 0x0000 glut_SKIP_STALE_MOTION_EVENTS :: GLenum glut_SKIP_STALE_MOTION_EVENTS = 0x0204 glut_SRGB :: CUInt glut_SRGB = 0x1000 glut_STENCIL :: CUInt glut_STENCIL = 0x0020 glut_STEREO :: CUInt glut_STEREO = 0x0100 glut_TRANSPARENT_INDEX :: GLenum glut_TRANSPARENT_INDEX = 0x0323 glut_TRY_DIRECT_CONTEXT :: CInt glut_TRY_DIRECT_CONTEXT = 2 glut_UP :: CInt glut_UP = 0x0001 glut_USE_CURRENT_CONTEXT :: CInt glut_USE_CURRENT_CONTEXT = 1 glut_VERSION :: GLenum glut_VERSION = 0x01FC glut_VIDEO_RESIZE_HEIGHT :: GLenum glut_VIDEO_RESIZE_HEIGHT = 0x038D glut_VIDEO_RESIZE_HEIGHT_DELTA :: GLenum glut_VIDEO_RESIZE_HEIGHT_DELTA = 0x0389 glut_VIDEO_RESIZE_IN_USE :: GLenum glut_VIDEO_RESIZE_IN_USE = 0x0385 glut_VIDEO_RESIZE_POSSIBLE :: GLenum glut_VIDEO_RESIZE_POSSIBLE = 0x0384 glut_VIDEO_RESIZE_WIDTH :: GLenum glut_VIDEO_RESIZE_WIDTH = 0x038C glut_VIDEO_RESIZE_WIDTH_DELTA :: GLenum glut_VIDEO_RESIZE_WIDTH_DELTA = 0x0388 glut_VIDEO_RESIZE_X :: GLenum glut_VIDEO_RESIZE_X = 0x038A glut_VIDEO_RESIZE_X_DELTA :: GLenum glut_VIDEO_RESIZE_X_DELTA = 0x0386 glut_VIDEO_RESIZE_Y :: GLenum glut_VIDEO_RESIZE_Y = 0x038B glut_VIDEO_RESIZE_Y_DELTA :: GLenum glut_VIDEO_RESIZE_Y_DELTA = 0x0387 glut_VISIBLE :: CInt glut_VISIBLE = 0x0001 glut_WINDOW_ACCUM_ALPHA_SIZE :: GLenum glut_WINDOW_ACCUM_ALPHA_SIZE = 0x0072 glut_WINDOW_ACCUM_BLUE_SIZE :: GLenum glut_WINDOW_ACCUM_BLUE_SIZE = 0x0071 glut_WINDOW_ACCUM_GREEN_SIZE :: GLenum glut_WINDOW_ACCUM_GREEN_SIZE = 0x0070 glut_WINDOW_ACCUM_RED_SIZE :: GLenum glut_WINDOW_ACCUM_RED_SIZE = 0x006F glut_WINDOW_ALPHA_SIZE :: GLenum glut_WINDOW_ALPHA_SIZE = 0x006E glut_WINDOW_BLUE_SIZE :: GLenum glut_WINDOW_BLUE_SIZE = 0x006D glut_WINDOW_BORDER_WIDTH :: GLenum glut_WINDOW_BORDER_WIDTH = 0x01FA glut_WINDOW_BUFFER_SIZE :: GLenum glut_WINDOW_BUFFER_SIZE = 0x0068 glut_WINDOW_COLORMAP_SIZE :: GLenum glut_WINDOW_COLORMAP_SIZE = 0x0077 glut_WINDOW_CURSOR :: GLenum glut_WINDOW_CURSOR = 0x007A glut_WINDOW_DEPTH_SIZE :: GLenum glut_WINDOW_DEPTH_SIZE = 0x006A glut_WINDOW_DOUBLEBUFFER :: GLenum glut_WINDOW_DOUBLEBUFFER = 0x0073 glut_WINDOW_FORMAT_ID :: GLenum glut_WINDOW_FORMAT_ID = 0x007B glut_WINDOW_GREEN_SIZE :: GLenum glut_WINDOW_GREEN_SIZE = 0x006C glut_WINDOW_HEADER_HEIGHT :: GLenum glut_WINDOW_HEADER_HEIGHT = 0x01FB glut_WINDOW_HEIGHT :: GLenum glut_WINDOW_HEIGHT = 0x0067 glut_WINDOW_NUM_CHILDREN :: GLenum glut_WINDOW_NUM_CHILDREN = 0x0076 glut_WINDOW_NUM_SAMPLES :: GLenum glut_WINDOW_NUM_SAMPLES = 0x0078 glut_WINDOW_PARENT :: GLenum glut_WINDOW_PARENT = 0x0075 glut_WINDOW_RED_SIZE :: GLenum glut_WINDOW_RED_SIZE = 0x006B glut_WINDOW_RGBA :: GLenum glut_WINDOW_RGBA = 0x0074 glut_WINDOW_STENCIL_SIZE :: GLenum glut_WINDOW_STENCIL_SIZE = 0x0069 glut_WINDOW_STEREO :: GLenum glut_WINDOW_STEREO = 0x0079 glut_WINDOW_WIDTH :: GLenum glut_WINDOW_WIDTH = 0x0066 glut_WINDOW_X :: GLenum glut_WINDOW_X = 0x0064 glut_WINDOW_Y :: GLenum glut_WINDOW_Y = 0x0065 GLUT-2.7.0.16/src/Graphics/UI/GLUT/Types.hs0000644000000000000000000000721513255126367016004 0ustar0000000000000000{-# OPTIONS_HADDOCK hide #-} -------------------------------------------------------------------------------- -- | -- Module : Graphics.UI.GLUT.Types -- Copyright : (c) Sven Panne 2002-2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- This is a purely internal module with miscellaneous types which don\'t really -- have a good place elsewhere. -- -------------------------------------------------------------------------------- module Graphics.UI.GLUT.Types ( Window(..), -- constructor used only internally Relation(..), relationToString, -- used only internally MouseButton(..), marshalMouseButton, unmarshalMouseButton -- used only internally ) where import Foreign.C.Types import Graphics.UI.GLUT.Raw -------------------------------------------------------------------------------- -- | An opaque identifier for a top-level window or a subwindow. newtype Window = Window CInt deriving ( Eq, Ord, Show ) -------------------------------------------------------------------------------- -- | A relation between a 'Graphics.UI.GLUT.Initialization.DisplayCapability' -- and a numeric value. data Relation = IsEqualTo -- ^ Equal. | IsNotEqualTo -- ^ Not equal. | IsLessThan -- ^ Less than and preferring larger difference (the least -- is best). | IsNotGreaterThan -- ^ Less than or equal and preferring larger difference -- (the least is best). | IsGreaterThan -- ^ Greater than and preferring larger differences (the -- most is best). | IsAtLeast -- ^ Greater than or equal and preferring more instead of -- less. This relation is useful for allocating -- resources like color precision or depth buffer -- precision where the maximum precision is generally -- preferred. Contrast with 'IsNotLessThan' relation. | IsNotLessThan -- ^ Greater than or equal but preferring less instead of -- more. This relation is useful for allocating -- resources such as stencil bits or auxillary color -- buffers where you would rather not over-allocate. deriving ( Eq, Ord, Show ) relationToString :: Relation -> String relationToString IsEqualTo = "=" relationToString IsNotEqualTo = "!=" relationToString IsLessThan = "<" relationToString IsNotGreaterThan = "<=" relationToString IsGreaterThan = ">" relationToString IsAtLeast = ">=" relationToString IsNotLessThan = "~" -------------------------------------------------------------------------------- -- | Mouse buttons, including a wheel data MouseButton = LeftButton | MiddleButton | RightButton | WheelUp | WheelDown | AdditionalButton Int deriving ( Eq, Ord, Show ) marshalMouseButton :: MouseButton -> CInt marshalMouseButton x = case x of LeftButton -> glut_LEFT_BUTTON MiddleButton -> glut_MIDDLE_BUTTON RightButton -> glut_RIGHT_BUTTON WheelUp -> glut_WHEEL_UP WheelDown -> glut_WHEEL_DOWN AdditionalButton b -> fromIntegral b unmarshalMouseButton :: CInt -> MouseButton unmarshalMouseButton x | x == glut_LEFT_BUTTON = LeftButton | x == glut_MIDDLE_BUTTON = MiddleButton | x == glut_RIGHT_BUTTON = RightButton | x == glut_WHEEL_UP = WheelUp | x == glut_WHEEL_DOWN = WheelDown | otherwise = AdditionalButton (fromIntegral x) glut_WHEEL_UP :: CInt glut_WHEEL_UP = 3 glut_WHEEL_DOWN :: CInt glut_WHEEL_DOWN = 4 GLUT-2.7.0.16/cbits/HsGLUT.c0000644000000000000000000001017413255126367013241 0ustar0000000000000000/* ----------------------------------------------------------------------------- * * Module : C support for Graphics.UI.GLUT.Raw * Copyright : (c) Sven Panne 2002-2018 * License : BSD3 * * Maintainer : Sven Panne * Stability : stable * Portability : portable * * -------------------------------------------------------------------------- */ #if defined(USE_GETPROCADDRESS) #define WIN32_LEAN_AND_MEAN #include static LPCTSTR libNames[] = { /* Try to load freeglut first, it has a few extra features compared to classic GLUT. */ TEXT("freeglut"), /* The MinGW-w64 version of freeglut prefixes "lib" onto the DLL name. */ TEXT("libfreeglut"), /* If no freeglut version is found, try plain old glut32 instead. */ TEXT("glut32") }; void* hs_GLUT_getProcAddress(const char *name) { static int firstTime = 1; static HMODULE handle = NULL; if (firstTime) { int i, numNames = (int)(sizeof(libNames) / sizeof(libNames[0])); firstTime = 0; for (i = 0; (!handle) && (i < numNames); ++i) { handle = LoadLibrary(libNames[i]); } } return handle ? GetProcAddress(handle, name) : NULL; } /* -------------------------------------------------------------------------- */ #elif defined(USE_DLSYM) #include #include static const char* libNames[] = { #ifdef __APPLE__ /* Try to use freeglut, checking the LD_LIBRARY_PATH */ "libglut.dylib", /* Try public framework path first. */ "/Library/Frameworks/GLUT.framework/GLUT", /* If the public path failed, try the system framework path. */ "/System/Library/Frameworks/GLUT.framework/GLUT" #else "libglut.so", "libglut.so.3" #endif }; void* hs_GLUT_getProcAddress(const char *name) { static int firstTime = 1; static void *handle = NULL; if (firstTime) { int i, numNames = (int)(sizeof(libNames) / sizeof(libNames[0])); firstTime = 0; for (i = 0; (!handle) && (i < numNames); ++i) { handle = dlopen(libNames[i], RTLD_LAZY | RTLD_GLOBAL); } } return handle ? dlsym(handle, name) : NULL; } /* -------------------------------------------------------------------------- */ #else #error "Don't know how to retrieve GLUT entries" #endif /* -------------------------------------------------------------------------- */ /* Note: This #if below is in sync with freeglut_std.h, classic GLUT simply used #if defined(_WIN32). */ #if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WATCOMC__) #define INIT_FONT(name,num) hs_##name = ((void*)(num)) #else #define INIT_FONT(name,num) hs_##name = hs_GLUT_getProcAddress(#name) #endif void* hs_GLUT_marshalBitmapFont(int fontID) { static int firstTime = 1; static void *hs_glutBitmap9By15 = NULL; static void *hs_glutBitmap8By13 = NULL; static void *hs_glutBitmapTimesRoman10 = NULL; static void *hs_glutBitmapTimesRoman24 = NULL; static void *hs_glutBitmapHelvetica10 = NULL; static void *hs_glutBitmapHelvetica12 = NULL; static void *hs_glutBitmapHelvetica18 = NULL; if (firstTime) { firstTime = 0; INIT_FONT(glutBitmap9By15, 0x0002); INIT_FONT(glutBitmap8By13, 0x0003); INIT_FONT(glutBitmapTimesRoman10, 0x0004); INIT_FONT(glutBitmapTimesRoman24, 0x0005); INIT_FONT(glutBitmapHelvetica10, 0x0006); INIT_FONT(glutBitmapHelvetica12, 0x0007); INIT_FONT(glutBitmapHelvetica18, 0x0008); } switch (fontID) { case 0 : return hs_glutBitmap8By13; case 1 : return hs_glutBitmap9By15; case 2 : return hs_glutBitmapTimesRoman10; case 3 : return hs_glutBitmapTimesRoman24; case 4 : return hs_glutBitmapHelvetica10; case 5 : return hs_glutBitmapHelvetica12; case 6 : return hs_glutBitmapHelvetica18; } return (void*)0; } void* hs_GLUT_marshalStrokeFont(int fontID) { static int firstTime = 1; static void *hs_glutStrokeRoman = NULL; static void *hs_glutStrokeMonoRoman = NULL; if (firstTime) { firstTime = 0; INIT_FONT(glutStrokeRoman, 0x0000); INIT_FONT(glutStrokeMonoRoman, 0x0001); } switch (fontID) { case 0 : return hs_glutStrokeRoman; case 1 : return hs_glutStrokeMonoRoman; } return (void*)0; } GLUT-2.7.0.16/examples/RedBook8/Chapter01/Triangles.hs0000644000000000000000000000441413255126367020171 0ustar0000000000000000{- Triangles.hs (adapted from triangles.cpp which is (c) The Red Book Authors.) Copyright (c) Sven Panne 2018 This file is part of HOpenGL and distributed under a BSD-style license See the file GLUT/LICENSE Our first OpenGL program. -} import Control.Monad import Foreign.Marshal.Array import Foreign.Ptr import Foreign.Storable import Graphics.UI.GLUT import Prelude hiding ( init ) import LoadShaders bufferOffset :: Integral a => a -> Ptr b bufferOffset = plusPtr nullPtr . fromIntegral data Descriptor = Descriptor VertexArrayObject ArrayIndex NumArrayIndices init :: IO Descriptor init = do triangles <- genObjectName bindVertexArrayObject $= Just triangles let vertices = [ Vertex2 (-0.90) (-0.90), -- Triangle 1 Vertex2 0.85 (-0.90), Vertex2 (-0.90) 0.85 , Vertex2 0.90 (-0.85), -- Triangle 2 Vertex2 0.90 0.90 , Vertex2 (-0.85) 0.90 ] :: [Vertex2 GLfloat] numVertices = length vertices vertexSize = sizeOf (head vertices) arrayBuffer <- genObjectName bindBuffer ArrayBuffer $= Just arrayBuffer withArray vertices $ \ptr -> do let size = fromIntegral (numVertices * vertexSize) bufferData ArrayBuffer $= (size, ptr, StaticDraw) program <- loadShaders [ ShaderInfo VertexShader (FileSource "triangles.vert"), ShaderInfo FragmentShader (FileSource "triangles.frag")] currentProgram $= Just program let firstIndex = 0 vPosition = AttribLocation 0 vertexAttribPointer vPosition $= (ToFloat, VertexArrayDescriptor 2 Float 0 (bufferOffset (firstIndex * vertexSize))) vertexAttribArray vPosition $= Enabled return $ Descriptor triangles (fromIntegral firstIndex) (fromIntegral numVertices) display :: Descriptor -> DisplayCallback display (Descriptor triangles firstIndex numVertices) = do clear [ ColorBuffer ] bindVertexArrayObject $= Just triangles drawArrays Triangles firstIndex numVertices flush main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ RGBAMode ] initialWindowSize $= Size 512 512 initialContextVersion $= (4, 3) initialContextProfile $= [ CoreProfile ] _ <- createWindow progName descriptor <- init displayCallback $= display descriptor mainLoop GLUT-2.7.0.16/examples/RedBook8/common/LoadShaders.hs0000644000000000000000000000561313255126367020175 0ustar0000000000000000-------------------------------------------------------------------------------- -- | -- Module : LoadShaders -- Copyright : (c) Sven Panne 2018 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -- Utilities for shader handling, adapted from LoadShaders.cpp which is (c) The -- Red Book Authors. -- -------------------------------------------------------------------------------- module LoadShaders ( ShaderSource(..), ShaderInfo(..), loadShaders ) where import Control.Exception import Control.Monad import qualified Data.ByteString as B import Graphics.UI.GLUT -------------------------------------------------------------------------------- -- | The source of the shader source code. data ShaderSource = ByteStringSource B.ByteString -- ^ The shader source code is directly given as a 'B.ByteString'. | StringSource String -- ^ The shader source code is directly given as a 'String'. | FileSource FilePath -- ^ The shader source code is located in the file at the given 'FilePath'. deriving ( Eq, Ord, Show ) getSource :: ShaderSource -> IO B.ByteString getSource (ByteStringSource bs) = return bs getSource (StringSource str) = return $ packUtf8 str getSource (FileSource path) = B.readFile path -------------------------------------------------------------------------------- -- | A description of a shader: The type of the shader plus its source code. data ShaderInfo = ShaderInfo ShaderType ShaderSource deriving ( Eq, Ord, Show ) -------------------------------------------------------------------------------- -- | Create a new program object from the given shaders, throwing an -- 'IOException' if something goes wrong. loadShaders :: [ShaderInfo] -> IO Program loadShaders infos = createProgram `bracketOnError` deleteObjectName $ \program -> do loadCompileAttach program infos linkAndCheck program return program linkAndCheck :: Program -> IO () linkAndCheck = checked linkProgram linkStatus programInfoLog "link" loadCompileAttach :: Program -> [ShaderInfo] -> IO () loadCompileAttach _ [] = return () loadCompileAttach program (ShaderInfo shType source : infos) = createShader shType `bracketOnError` deleteObjectName $ \shader -> do src <- getSource source shaderSourceBS shader $= src compileAndCheck shader attachShader program shader loadCompileAttach program infos compileAndCheck :: Shader -> IO () compileAndCheck = checked compileShader compileStatus shaderInfoLog "compile" checked :: (t -> IO ()) -> (t -> GettableStateVar Bool) -> (t -> GettableStateVar String) -> String -> t -> IO () checked action getStatus getInfoLog message object = do action object ok <- get (getStatus object) unless ok $ do infoLog <- get (getInfoLog object) fail (message ++ " log: " ++ infoLog) GLUT-2.7.0.16/examples/RedBook4/Wrap.hs0000644000000000000000000001052413255126367015416 0ustar0000000000000000{- Wrap.hs (adapted from wrap.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program texture maps a checkerboard image onto two rectangles. This program demonstrates the wrapping modes, if the texture coordinates fall outside 0.0 and 1.0. Interaction: Pressing the 's' and 'S' keys switch the wrapping between clamping and repeating for the s parameter. The 't' and 'T' keys control the wrapping for the t parameter. Texture objects are only used when GL_EXT_texture_object is supported. -} import Control.Monad ( when ) import Data.Maybe ( isJust ) import Data.Bits ( (.&.) ) import Foreign ( withArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT -- Create checkerboard image checkImageSize :: TextureSize2D checkImageSize = TextureSize2D 64 64 withCheckImage :: TextureSize2D -> GLsizei -> (GLubyte -> (Color4 GLubyte)) -> (PixelData (Color4 GLubyte) -> IO ()) -> IO () withCheckImage (TextureSize2D w h) n f act = withArray [ f c | i <- [ 0 .. w - 1 ], j <- [ 0 .. h - 1 ], let c | (i .&. n) == (j .&. n) = 0 | otherwise = 255 ] $ act. PixelData RGBA UnsignedByte myInit :: IO (Maybe TextureObject) myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat depthFunc $= Just Less rowAlignment Unpack $= 1 exts <- get glExtensions mbTexName <- if "GL_EXT_texture_object" `elem` exts then fmap Just genObjectName else return Nothing when (isJust mbTexName) $ textureBinding Texture2D $= mbTexName textureWrapMode Texture2D S $= (Repeated, Repeat) textureWrapMode Texture2D T $= (Repeated, Repeat) textureFilter Texture2D $= ((Nearest, Nothing), Nearest) withCheckImage checkImageSize 0x8 (\c -> Color4 c c c 255) $ texImage2D Texture2D NoProxy 0 RGBA' checkImageSize 0 return mbTexName display :: Maybe TextureObject -> DisplayCallback display mbTexName = do clear [ ColorBuffer, DepthBuffer ] texture Texture2D $= Enabled textureFunction $= Decal when (isJust mbTexName) $ textureBinding Texture2D $= mbTexName -- resolve overloading, not needed in "real" programs let texCoord2f = texCoord :: TexCoord2 GLfloat -> IO () vertex3f = vertex :: Vertex3 GLfloat -> IO () renderPrimitive Quads $ do texCoord2f (TexCoord2 0 0); vertex3f (Vertex3 (-2.0) (-1.0) 0.0 ) texCoord2f (TexCoord2 0 3); vertex3f (Vertex3 (-2.0) 1.0 0.0 ) texCoord2f (TexCoord2 3 3); vertex3f (Vertex3 0.0 1.0 0.0 ) texCoord2f (TexCoord2 3 0); vertex3f (Vertex3 0.0 (-1.0) 0.0 ) texCoord2f (TexCoord2 0 0); vertex3f (Vertex3 1.0 (-1.0) 0.0 ) texCoord2f (TexCoord2 0 3); vertex3f (Vertex3 1.0 1.0 0.0 ) texCoord2f (TexCoord2 3 3); vertex3f (Vertex3 2.41421 1.0 (-1.41421)) texCoord2f (TexCoord2 3 0); vertex3f (Vertex3 2.41421 (-1.0) (-1.41421)) flush texture Texture2D $= Disabled reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 60 (fromIntegral w / fromIntegral h) 1 30 matrixMode $= Modelview 0 loadIdentity translate (Vector3 0 0 (-3.6 :: GLfloat)) keyboard :: KeyboardMouseCallback keyboard (Char 's' ) Down _ _ = setClamping S Clamp keyboard (Char 'S' ) Down _ _ = setClamping S Repeat keyboard (Char 't' ) Down _ _ = setClamping T Clamp keyboard (Char 'T' ) Down _ _ = setClamping T Repeat keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () setClamping :: TextureCoordName -> Clamping -> IO () setClamping coord clamp = do textureWrapMode Texture2D coord $= (Repeated, clamp); postRedisplay Nothing main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 250 250 initialWindowPosition $= Position 100 100 _ <- createWindow progName mbTexName <- myInit displayCallback $= display mbTexName reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/VArray.hs0000644000000000000000000001057113255126367015713 0ustar0000000000000000{- VArray.hs (adapted from varray.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates vertex arrays. -} import Control.Monad ( when ) import Data.IORef ( IORef, newIORef ) import Foreign ( Ptr, newArray ) import System.Exit ( exitFailure, exitWith, ExitCode(..) ) import Graphics.UI.GLUT data SetupMethod = Pointer | Interleaved deriving ( Eq, Bounded, Enum ) data DerefMethod = DrawArray | ArrayElement | DrawElements deriving ( Eq, Bounded, Enum ) makeVertices :: IO (Ptr (Vertex2 GLint)) makeVertices = newArray [ Vertex2 25 25, Vertex2 100 325, Vertex2 175 25, Vertex2 175 325, Vertex2 250 25, Vertex2 325 325 ] makeColors :: IO (Ptr (Color3 GLfloat)) makeColors = newArray [ Color3 1.0 0.2 0.2, Color3 0.2 0.2 1.0, Color3 0.8 1.0 0.2, Color3 0.75 0.75 0.75, Color3 0.35 0.35 0.35, Color3 0.5 0.5 0.5 ] makeIntertwined :: IO (Ptr GLfloat) makeIntertwined = newArray [ 1.0, 0.2, 1.0, 100.0, 100.0, 0.0, 1.0, 0.2, 0.2, 0.0, 200.0, 0.0, 1.0, 1.0, 0.2, 100.0, 300.0, 0.0, 0.2, 1.0, 0.2, 200.0, 300.0, 0.0, 0.2, 1.0, 1.0, 300.0, 200.0, 0.0, 0.2, 0.2, 1.0, 200.0, 100.0, 0.0 ] makeIndices :: IO (Ptr GLuint) makeIndices = newArray [ 0, 1, 3, 4 ] data State = State { vertices :: Ptr (Vertex2 GLint), colors :: Ptr (Color3 GLfloat), intertwined :: Ptr GLfloat, indices :: Ptr GLuint, setupMethod :: IORef SetupMethod, derefMethod :: IORef DerefMethod } makeState :: IO State makeState = do v <- makeVertices c <- makeColors i <- makeIntertwined n <- makeIndices s <- newIORef Pointer d <- newIORef DrawArray return $ State { vertices = v, colors = c, intertwined = i, indices = n, setupMethod = s, derefMethod = d } setup :: State -> IO () setup state = do s <- get (setupMethod state) case s of Pointer -> do clientState VertexArray $= Enabled clientState ColorArray $= Enabled arrayPointer VertexArray $= VertexArrayDescriptor 2 Int 0 (vertices state) arrayPointer ColorArray $= VertexArrayDescriptor 3 Float 0 (colors state) Interleaved -> interleavedArrays C3fV3f 0 (intertwined state) myInit :: State -> IO () myInit state = do clearColor $= Color4 0 0 0 0 shadeModel $= Smooth setup state display :: State -> DisplayCallback display state = do clear [ ColorBuffer ] d <- get (derefMethod state) case d of DrawArray -> drawArrays Triangles 0 6 ArrayElement -> renderPrimitive Triangles $ mapM_ arrayElement [ 2, 3, 5 ] DrawElements -> drawElements Polygon 4 UnsignedInt (indices state) flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho2D 0 (fromIntegral w) 0 (fromIntegral h) -- the following line is not in the original example, but it's good style... matrixMode $= Modelview 0 keyboardMouse :: State -> KeyboardMouseCallback keyboardMouse state (MouseButton LeftButton) Down _ _ = do setupMethod state $~ nextValue setup state postRedisplay Nothing keyboardMouse state (MouseButton _) Down _ _ = do derefMethod state $~ nextValue postRedisplay Nothing keyboardMouse _ (Char '\27') Down _ _ = exitWith ExitSuccess keyboardMouse _ _ _ _ _ = return () nextValue :: (Eq a, Bounded a, Enum a) => a -> a nextValue x = if x == maxBound then minBound else succ x main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 350 350 initialWindowPosition $= Position 100 100 _ <- createWindow progName -- we have to do this *after* createWindow, otherwise we have no OpenGL context version <- get (majorMinor glVersion) when (version == (1,0)) $ do putStrLn "This program demonstrates a feature which is not in OpenGL Version 1.0." putStrLn "If your implementation of OpenGL Version 1.0 has the right extensions," putStrLn "you may be able to modify this program to make it run." exitFailure state <- makeState myInit state displayCallback $= display state reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboardMouse state) mainLoop GLUT-2.7.0.16/examples/RedBook4/UnProject.hs0000644000000000000000000000405213255126367016415 0ustar0000000000000000{- UnProject.hs (adapted from unproject.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE When the left mouse button is pressed, this program reads the mouse position and determines two 3D points from which it was transformed. Very little is displayed. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT display :: DisplayCallback display = do clear [ ColorBuffer ] flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 45 (fromIntegral w / fromIntegral h) 1 100 matrixMode $= Modelview 0 loadIdentity keyboardMouse :: KeyboardMouseCallback keyboardMouse (MouseButton LeftButton) Down _ (Position x y) = do v@(_, Size _ h) <- get viewport mvMatrix <- get (matrix (Just (Modelview 0))) :: IO (GLmatrix GLdouble) projMatrix <- get (matrix (Just Projection)) :: IO (GLmatrix GLdouble) let realY = fromIntegral h - y -1 putStrLn ("Coordinates at cursor are (" ++ show x ++", " ++ show realY ++ ")") w0 <- unProject (Vertex3 (fromIntegral x) (fromIntegral realY) 0) mvMatrix projMatrix v putStrLn ("World coords at z=0.0 are " ++ show w0) w1 <- unProject (Vertex3 (fromIntegral x) (fromIntegral realY) 1) mvMatrix projMatrix v putStrLn ("World coords at z=1.0 are " ++ show w1) keyboardMouse (MouseButton RightButton) Down _ _ = exitWith ExitSuccess keyboardMouse (Char '\27') Down _ _ = exitWith ExitSuccess keyboardMouse _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName displayCallback $= display reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboardMouse mainLoop GLUT-2.7.0.16/examples/RedBook4/Trim.hs0000644000000000000000000000736213255126367015426 0ustar0000000000000000{- Trim.hs (adapted from trim.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program draws a NURBS surface in the shape of a symmetrical hill, using both a NURBS curve and pwl (piecewise linear) curve to trim part of the surface. NOTE: This example does NOT demonstrate the final NURBS API, it's currently just a test for the internals... -} import Foreign.Marshal ( withArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT -- The control points of the surface form a small hill and -- range from -3 to +3 in x, y, and z. ctlPoints :: [[Vertex3 GLfloat]] ctlPoints = [ [ Vertex3 (2 * u - 3) (2 * v - 3) (if (u == 1 || u ==2) && (v == 1 || v == 2) then 3 else -3) | v <- [ 0 .. 3 ] ] | u <- [ 0 .. 3 ]] myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 materialDiffuse Front $= Color4 0.7 0.7 0.7 1 materialSpecular Front $= Color4 1 1 1 1 materialShininess Front $= 100 lighting $= Enabled light (Light 0) $= Enabled depthFunc $= Just Less autoNormal $= Enabled normalize $= Enabled -------------------------------------------------------------------------------- display :: DisplayCallback display = do let knots = [ 0, 0, 0, 0, 1, 1, 1, 1 ] :: [GLfloat] edgePt = -- counter clockwise [ Vertex2 0 0, Vertex2 1 0, Vertex2 1 1, Vertex2 0 1, Vertex2 0 0 ] :: [Vertex2 GLfloat] curvePt = -- clockwise [ Vertex2 0.25 0.5, Vertex2 0.25 0.75, Vertex2 0.75 0.75, Vertex2 0.75 0.5 ] :: [Vertex2 GLfloat] curveKnots = [ 0, 0, 0, 0, 1, 1, 1, 1 ] :: [GLfloat] pwlPt = -- clockwise [Vertex2 0.75 0.5, Vertex2 0.5 0.25, Vertex2 0.25 0.5 ] :: [Vertex2 GLfloat] clear [ ColorBuffer, DepthBuffer ] preservingMatrix $ do rotate (330 :: GLfloat) (Vector3 1 0 0) scale 0.5 0.5 (0.5 :: GLfloat) withNURBSObj () $ \nurbsObj -> do setSamplingMethod nurbsObj (PathLength 25) setDisplayMode' nurbsObj Fill' checkForNURBSError nurbsObj $ nurbsBeginEndSurface nurbsObj $ withArray (concat ctlPoints) $ \cBuf -> withArray knots $ \kBuf -> do nurbsSurface nurbsObj 8 kBuf 8 kBuf (4 * 3) 3 cBuf 4 4 nurbsBeginEndTrim nurbsObj $ withArray edgePt $ \edgePtBuf -> pwlCurve nurbsObj 5 edgePtBuf 2 nurbsBeginEndTrim nurbsObj $ do withArray curveKnots $ \curveKnotsBuf -> withArray curvePt $ \curvePtBuf -> trimmingCurve nurbsObj 8 curveKnotsBuf 2 curvePtBuf 4 withArray pwlPt $ \pwlPtBuf -> pwlCurve nurbsObj 3 pwlPtBuf 2 flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 45 (fromIntegral w / fromIntegral h) 3 8 matrixMode $= Modelview 0 loadIdentity translate (Vector3 0 0 (-5 :: GLfloat)) keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () -- Main Loop main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit reshapeCallback $= Just reshape displayCallback $= display keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/Torus.hs0000644000000000000000000000546213255126367015626 0ustar0000000000000000{- Torus.hs (adapted from torus.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates the creation of a display list. -} import Data.Char ( toLower ) import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { spinX, spinY :: IORef GLfloat } makeState :: IO State makeState = do x <- newIORef 0 y <- newIORef 0 return $ State { spinX = x, spinY = y } torus :: Int -> Int -> IO () torus numC numT = do let stepC = 2 * pi / fromIntegral numC :: GLfloat stepT = 2 * pi / fromIntegral numT flip mapM_ [ 0 .. numC - 1 ] $ \i -> renderPrimitive QuadStrip $ flip mapM_ [ 0 .. numT ] $ \j -> flip mapM_ [ 1, 0 ] $ \k -> do let s = (fromIntegral ((i + k) `mod` numC) + 0.5) * stepC t = (fromIntegral ( j `mod` numT) ) * stepT x = (1 + 0.1 * cos s) * cos t y = (1 + 0.1 * cos s) * sin t z = 0.1 * sin s vertex (Vertex3 x y z) myInit :: IO DisplayList myInit = do theTorus <- defineNewList Compile $ torus 8 25 shadeModel $= Flat clearColor $= Color4 0 0 0 0 return theTorus display :: State -> DisplayList -> DisplayCallback display state theTorus = do clear [ ColorBuffer ] loadIdentity lookAt (Vertex3 0 0 10) (Vertex3 0 0 0) (Vector3 0 1 0) x <- get (spinX state) rotate x (Vector3 1 0 0) y <- get (spinY state) rotate y (Vector3 0 1 0) color (Color3 1 1 (1 :: GLfloat)) callList theTorus flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 30 (fromIntegral w / fromIntegral h) 1 100 matrixMode $= Modelview 0 incSpin :: IORef GLfloat -> IO () incSpin spinRef = do let wrap n s = if s > n then s - n else s spinRef $~ (wrap 360 . (+ 30)) postRedisplay Nothing keyboard :: State -> KeyboardMouseCallback keyboard state (Char c) Down _ _ = case toLower c of 'x' -> incSpin (spinX state) 'y' -> incSpin (spinY state) 'i' -> do spinX state $= 0; spinY state $= 0; postRedisplay Nothing '\27' -> exitWith ExitSuccess _ -> return () keyboard _ _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 200 200 _ <- createWindow progName state <- makeState theTorus <- myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard state) displayCallback $= display state theTorus mainLoop GLUT-2.7.0.16/examples/RedBook4/TextureSurf.hs0000644000000000000000000000664013255126367017011 0ustar0000000000000000{- TextureSurf.hs (adapted from texturesurf.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program uses evaluators to generate a curved surface and automatically generated texture coordinates. -} import Data.List ( transpose ) import Foreign ( withArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT ctrlPoints :: [[Vertex3 GLfloat]] ctrlPoints = [ [ Vertex3 (-1.5) (-1.5) 4.0, Vertex3 (-0.5) (-1.5) 2.0, Vertex3 0.5 (-1.5) (-1.0), Vertex3 1.5 (-1.5) 2.0 ], [ Vertex3 (-1.5) (-0.5) 1.0, Vertex3 (-0.5) (-0.5) 3.0, Vertex3 0.5 (-0.5) 0.0, Vertex3 1.5 (-0.5) (-1.0) ], [ Vertex3 (-1.5) 0.5 4.0, Vertex3 (-0.5) 0.5 0.0, Vertex3 0.5 0.5 3.0, Vertex3 1.5 0.5 4.0 ], [ Vertex3 (-1.5) 1.5 (-2.0), Vertex3 (-0.5) 1.5 (-2.0), Vertex3 0.5 1.5 0.0, Vertex3 1.5 1.5 (-1.0) ]] texPts :: [[TexCoord2 GLfloat]] texPts = [ [ TexCoord2 0 0, TexCoord2 0 1 ], [ TexCoord2 1 0, TexCoord2 1 1 ]] display :: DisplayCallback display = do clear [ ColorBuffer, DepthBuffer ] color (Color3 1 1 1 :: Color3 GLfloat) evalMesh2 Fill (0, 20) (0, 20) flush imageSize :: TextureSize2D imageSize = TextureSize2D 64 64 withImage :: (PixelData (Color3 GLubyte) -> IO ()) -> IO () withImage act = withArray [ Color3 (s (sin ti)) (s (cos (2 * tj))) (s (cos (ti + tj))) | i <- [ 0 .. fromIntegral w - 1 ], let ti = 2 * pi * i / fromIntegral w, j <- [ 0 .. fromIntegral h - 1 ], let tj = 2 * pi * j / fromIntegral h ] $ act . PixelData RGB UnsignedByte where (TextureSize2D w h) = imageSize s :: Double -> GLubyte s x = truncate (127 * (1 + x)) myInit :: IO () myInit = do m <- newMap2 (0, 1) (0, 1) (transpose ctrlPoints) map2 $= Just (m :: GLmap2 Vertex3 GLfloat) t <- newMap2 (0, 1) (0, 1) (transpose texPts) map2 $= Just (t :: GLmap2 TexCoord2 GLfloat) mapGrid2 $= ((20, (0, 1)), (20, (0, 1 :: GLfloat))) textureFunction $= Decal textureWrapMode Texture2D S $= (Repeated, Repeat) textureWrapMode Texture2D T $= (Repeated, Repeat) textureFilter Texture2D $= ((Nearest, Nothing), Nearest) withImage $ texImage2D Texture2D NoProxy 0 RGB' imageSize 0 texture Texture2D $= Enabled depthFunc $= Just Less shadeModel $= Flat reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho (-4.0) 4.0 (-4.0*hf/wf) (4.0*hf/wf) (-4.0) 4.0 else ortho (-4.0*wf/hf) (4.0*wf/hf) (-4.0) 4.0 (-4.0) 4.0 matrixMode $= Modelview 0 loadIdentity rotate (85 :: GLfloat) (Vector3 1 1 1) keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit displayCallback $= display reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/Texture3D.hs0000644000000000000000000000664013255126367016340 0ustar0000000000000000{- Texture3D.hs (adapted from texture3d.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates using a three-dimensional texture. It creates a 3D texture and then renders two rectangles with different texture coordinates to obtain different "slices" of the 3D texture. -} import Control.Monad ( unless ) import Foreign ( withArray ) import System.Exit ( exitFailure, exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT -- Create checkerboard image imageSize :: TextureSize3D imageSize = TextureSize3D 16 16 16 withImage :: (PixelData (Color3 GLubyte) -> IO ()) -> IO () withImage act = withArray [ Color3 (s * 17) (t * 17) (r * 17) | r <- [ 0 .. fromIntegral d - 1 ], t <- [ 0 .. fromIntegral h - 1 ], s <- [ 0 .. fromIntegral w - 1 ] ] $ act . PixelData RGB UnsignedByte where (TextureSize3D w h d) = imageSize myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat depthFunc $= Just Less rowAlignment Unpack $= 1 texName <- genObjectName textureBinding Texture3D $= Just texName textureWrapMode Texture3D S $= (Repeated, Clamp) textureWrapMode Texture3D T $= (Repeated, Clamp) textureWrapMode Texture3D R $= (Repeated, Clamp) textureFilter Texture3D $= ((Nearest, Nothing), Nearest) withImage $ texImage3D Texture3D NoProxy 0 RGB' imageSize 0 texture Texture3D $= Enabled display :: DisplayCallback display = do clear [ ColorBuffer, DepthBuffer ] -- resolve overloading, not needed in "real" programs let texCoord3f = texCoord :: TexCoord3 GLfloat -> IO () vertex3f = vertex :: Vertex3 GLfloat -> IO () renderPrimitive Quads $ do texCoord3f (TexCoord3 0 0 0); vertex3f (Vertex3 (-2.25) (-1) 0) texCoord3f (TexCoord3 0 1 0); vertex3f (Vertex3 (-2.25) 1 0) texCoord3f (TexCoord3 1 1 1); vertex3f (Vertex3 (-0.25) 1 0) texCoord3f (TexCoord3 1 0 1); vertex3f (Vertex3 (-0.25) (-1) 0) texCoord3f (TexCoord3 0 0 1); vertex3f (Vertex3 0.25 (-1) 0) texCoord3f (TexCoord3 0 1 1); vertex3f (Vertex3 0.25 1 0) texCoord3f (TexCoord3 1 1 0); vertex3f (Vertex3 2.25 1 0) texCoord3f (TexCoord3 1 0 0); vertex3f (Vertex3 2.25 (-1) 0) flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 60 (fromIntegral w / fromIntegral h) 1 30 matrixMode $= Modelview 0 loadIdentity translate (Vector3 0 0 (-4 :: GLfloat)) keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 250 250 initialWindowPosition $= Position 100 100 _ <- createWindow progName -- we have to do this *after* createWindow, otherwise we have no OpenGL context exts <- get glExtensions unless ("GL_EXT_texture3D" `elem` exts) $ do putStrLn "Sorry, this demo requires the GL_EXT_texture3D extension." exitFailure myInit reshapeCallback $= Just reshape displayCallback $= display keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/TexSub.hs0000644000000000000000000001127413255126367015722 0ustar0000000000000000{- TexSub.hs (adapted from texsub.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program texture maps a checkerboard image onto two rectangles. This program clamps the texture, if the texture coordinates fall outside 0.0 and 1.0. If the s key is pressed, a texture subimage is used to alter the original texture. If the r key is pressed, the original texture is restored. -} import Control.Monad ( when ) import Data.Char ( toLower ) import Data.Bits ( (.&.) ) import Foreign ( newArray ) import System.Exit ( exitFailure, exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT checkImageSize, subImageSize :: TextureSize2D checkImageSize = TextureSize2D 64 64 subImageSize = TextureSize2D 16 16 type Image = PixelData (Color4 GLubyte) makeCheckImage :: TextureSize2D -> GLsizei -> (GLubyte -> (Color4 GLubyte)) -> IO Image makeCheckImage (TextureSize2D w h) n f = fmap (PixelData RGBA UnsignedByte) $ newArray [ f c | i <- [ 0 .. w - 1 ], j <- [ 0 .. h - 1 ], let c | (i .&. n) == (j .&. n) = 0 | otherwise = 255 ] myInit :: IO (TextureObject, Image, Image) myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat depthFunc $= Just Less checkImage <- makeCheckImage checkImageSize 0x8 (\c -> Color4 c c c 255) subImage <- makeCheckImage subImageSize 0x4 (\c -> Color4 c 0 0 255) rowAlignment Unpack $= 1 texName <- genObjectName textureBinding Texture2D $= Just texName textureWrapMode Texture2D S $= (Repeated, Repeat) textureWrapMode Texture2D T $= (Repeated, Repeat) textureFilter Texture2D $= ((Nearest, Nothing), Nearest) texImage2D Texture2D NoProxy 0 RGBA' checkImageSize 0 checkImage return (texName, checkImage, subImage) display :: TextureObject -> DisplayCallback display texName = do clear [ ColorBuffer, DepthBuffer ] texture Texture2D $= Enabled textureFunction $= Decal textureBinding Texture2D $= Just texName -- resolve overloading, not needed in "real" programs let texCoord2f = texCoord :: TexCoord2 GLfloat -> IO () vertex3f = vertex :: Vertex3 GLfloat -> IO () renderPrimitive Quads $ do texCoord2f (TexCoord2 0 0); vertex3f (Vertex3 (-2.0) (-1.0) 0.0 ) texCoord2f (TexCoord2 0 1); vertex3f (Vertex3 (-2.0) 1.0 0.0 ) texCoord2f (TexCoord2 1 1); vertex3f (Vertex3 0.0 1.0 0.0 ) texCoord2f (TexCoord2 1 0); vertex3f (Vertex3 0.0 (-1.0) 0.0 ) texCoord2f (TexCoord2 0 0); vertex3f (Vertex3 1.0 (-1.0) 0.0 ) texCoord2f (TexCoord2 0 1); vertex3f (Vertex3 1.0 1.0 0.0 ) texCoord2f (TexCoord2 1 1); vertex3f (Vertex3 2.41421 1.0 (-1.41421)) texCoord2f (TexCoord2 1 0); vertex3f (Vertex3 2.41421 (-1.0) (-1.41421)) flush texture Texture2D $= Disabled reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 60 (fromIntegral w / fromIntegral h) 1 30 matrixMode $= Modelview 0 loadIdentity translate (Vector3 0 0 (-3.6 :: GLfloat)) keyboard :: TextureObject -> Image -> Image -> KeyboardMouseCallback keyboard texName checkImage subImage (Char c) Down _ _ = case toLower c of 's' -> do textureBinding Texture2D $= Just texName texSubImage2D Texture2D 0 (TexturePosition2D 12 44) subImageSize subImage postRedisplay Nothing 'r' -> do textureBinding Texture2D $= Just texName texImage2D Texture2D NoProxy 0 RGBA' checkImageSize 0 checkImage postRedisplay Nothing '\27' -> exitWith ExitSuccess _ -> return () keyboard _ _ _ _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 250 250 initialWindowPosition $= Position 100 100 _ <- createWindow progName -- we have to do this *after* createWindow, otherwise we have no OpenGL context version <- get (majorMinor glVersion) when (version == (1,0)) $ do putStrLn "This program demonstrates a feature which is not in OpenGL Version 1.0." putStrLn "If your implementation of OpenGL Version 1.0 has the right extensions," putStrLn "you may be able to modify this program to make it run." exitFailure (texName, checkImage, subImage) <- myInit displayCallback $= display texName reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard texName checkImage subImage) mainLoop GLUT-2.7.0.16/examples/RedBook4/TexProx.hs0000644000000000000000000000377213255126367016125 0ustar0000000000000000{- TexProx.hs (adapted from texprox.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE The brief program illustrates use of texture proxies. This program only prints out some messages about whether certain size textures are supported and then exits. -} import Control.Monad ( when ) import Foreign.Ptr ( nullPtr ) import System.Exit ( exitFailure, exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT myInit :: IO () myInit = do let check = do ok <- get (textureProxyOK Texture2D 0) putStrLn ("proxy allocation " ++ if ok then "succeeded" else "failed") texImage2D Texture2D Proxy 0 RGBA8 (TextureSize2D 64 64) 0 (PixelData RGBA UnsignedByte nullPtr) check -- Note: We use a larger texture size here to demonstrate failure, -- modern graphic cards can handle the original size. texImage2D Texture2D Proxy 0 RGBA16 (TextureSize2D 8192 8192) 0 (PixelData RGBA UnsignedShort nullPtr) check display :: DisplayCallback display = exitWith ExitSuccess reshape :: ReshapeCallback reshape size = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName -- we have to do this *after* createWindow, otherwise we have no OpenGL context version <- get (majorMinor glVersion) when (version == (1,0)) $ do putStrLn "This program demonstrates a feature which is not in OpenGL Version 1.0." putStrLn "If your implementation of OpenGL Version 1.0 has the right extensions," putStrLn "you may be able to modify this program to make it run." exitFailure myInit displayCallback $= display reshapeCallback $= Just reshape mainLoop GLUT-2.7.0.16/examples/RedBook4/TexGen.hs0000644000000000000000000001073113255126367015677 0ustar0000000000000000{- TexGen.hs (adapted from texgen.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program draws a texture mapped teapot with automatically generated texture coordinates. The texture is rendered as stripes on the teapot. Initially, the object is drawn with texture coordinates based upon the object coordinates of the vertex and distance from the plane x = 0. Pressing the 'e' key changes the coordinate generation to eye coordinates of the vertex. Pressing the 'o' key switches it back to the object coordinates. Pressing the 's' key changes the plane to a slanted one (x + y + z = 0). Pressing the 'x' key switches it back to x = 0. -} import Control.Monad ( when ) import Data.Char ( toLower ) import Data.Maybe ( isJust ) import Foreign ( withArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT stripeImageWidth :: TextureSize1D stripeImageWidth = TextureSize1D 32 xEqualZero, slanted :: Plane GLdouble xEqualZero = Plane 1 0 0 0 slanted = Plane 1 1 1 0 withStripeImage :: (PixelData (Color4 GLubyte) -> IO a) -> IO a withStripeImage act = withArray [ Color4 (if j <= 4 then 255 else 0) (if j > 4 then 255 else 0) 0 255 | j <- [ 0 .. w - 1 ] ] $ act . PixelData RGBA UnsignedByte where TextureSize1D w = stripeImageWidth myInit :: IO (Maybe TextureObject) myInit = do clearColor $= Color4 0 0 0 0 depthFunc $= Just Less shadeModel $= Smooth rowAlignment Unpack $= 1 exts <- get glExtensions mbTexName <- if "GL_EXT_texture_object" `elem` exts then fmap Just genObjectName else return Nothing when (isJust mbTexName) $ textureBinding Texture1D $= mbTexName textureWrapMode Texture1D S $= (Repeated, Repeat) textureFilter Texture1D $= ((Linear', Nothing), Linear') withStripeImage $ texImage1D Texture1D NoProxy 0 RGBA' stripeImageWidth 0 textureFunction $= Modulate textureGenMode S $= Just (ObjectLinear xEqualZero) texture Texture1D $= Enabled lighting $= Enabled light (Light 0) $= Enabled autoNormal $= Enabled normalize $= Enabled frontFace $= CW cullFace $= Just Back materialShininess Front $= 64 return mbTexName display :: Maybe TextureObject -> DisplayCallback display mbTexName = do clear [ ColorBuffer, DepthBuffer ] preservingMatrix $ do rotate (45 :: GLfloat) (Vector3 0 0 1) when (isJust mbTexName) $ textureBinding Texture1D $= mbTexName renderObject Solid (Teapot 2) flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho (-3.5) 3.5 (-3.5*hf/wf) (3.5*hf/wf) (-3.5) 3.5 else ortho (-3.5*wf/hf) (3.5*wf/hf) (-3.5) 3.5 (-3.5) 3.5 matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char c) Down _ _ = case toLower c of 'e' -> setGenMode EyeLinear 'o' -> setGenMode ObjectLinear 's' -> setPlane slanted 'x' -> setPlane xEqualZero '\27' -> exitWith ExitSuccess _ -> return () keyboard _ _ _ _ = return () setGenMode :: (Plane GLdouble -> TextureGenMode) -> IO () setGenMode mode = do currentGenMode <- get (textureGenMode S) case currentGenMode of Just (EyeLinear plane) -> textureGenMode S $= Just (mode plane) Just (ObjectLinear plane) -> textureGenMode S $= Just (mode plane) _ -> error "setGenMode: should never happen..." postRedisplay Nothing setPlane :: Plane GLdouble -> IO () setPlane plane = do currentGenMode <- get (textureGenMode S) case currentGenMode of Just (EyeLinear _) -> textureGenMode S $= Just (EyeLinear plane) Just (ObjectLinear _) -> textureGenMode S $= Just (ObjectLinear plane) _ -> error "setPlane: should never happen..." postRedisplay Nothing main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 256 256 initialWindowPosition $= Position 100 100 _ <- createWindow progName mbTexName <- myInit displayCallback $= display mbTexName reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/TexBind.hs0000644000000000000000000001042413255126367016041 0ustar0000000000000000{- TexBind.hs (adapted from texbind.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates using textureBinding by creating and managing two textures. -} import Control.Monad ( when ) import Data.Bits ( (.&.) ) import Foreign ( withArray ) import System.Exit ( exitFailure, exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT -- Create checkerboard image checkImageSize :: TextureSize2D checkImageSize = TextureSize2D 64 64 withCheckImage :: TextureSize2D -> GLsizei -> (GLubyte -> (Color4 GLubyte)) -> (PixelData (Color4 GLubyte) -> IO ()) -> IO () withCheckImage (TextureSize2D w h) n f act = withArray [ f c | i <- [ 0 .. w - 1 ], j <- [ 0 .. h - 1 ], let c | (i .&. n) == (j .&. n) = 0 | otherwise = 255 ] $ act . PixelData RGBA UnsignedByte myInit :: IO (TextureObject, TextureObject) myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat depthFunc $= Just Less rowAlignment Unpack $= 1 [texName0, texName1] <- genObjectNames 2 textureBinding Texture2D $= Just texName0 textureWrapMode Texture2D S $= (Repeated, Clamp) textureWrapMode Texture2D T $= (Repeated, Clamp) textureFilter Texture2D $= ((Nearest, Nothing), Nearest) withCheckImage checkImageSize 0x08 (\c -> Color4 c c c 255) $ texImage2D Texture2D NoProxy 0 RGBA' checkImageSize 0 textureBinding Texture2D $= Just texName1 textureWrapMode Texture2D S $= (Repeated, Clamp) textureWrapMode Texture2D T $= (Repeated, Clamp) textureFilter Texture2D $= ((Nearest, Nothing), Nearest) textureFunction $= Decal withCheckImage checkImageSize 0x10 (\c -> Color4 c 0 0 255) $ texImage2D Texture2D NoProxy 0 RGBA' checkImageSize 0 texture Texture2D $= Enabled return (texName0, texName1) display :: (TextureObject, TextureObject) -> DisplayCallback display (texName0, texName1) = do clear [ ColorBuffer, DepthBuffer ] -- resolve overloading, not needed in "real" programs let texCoord2f = texCoord :: TexCoord2 GLfloat -> IO () vertex3f = vertex :: Vertex3 GLfloat -> IO () textureBinding Texture2D $= Just texName0 renderPrimitive Quads $ do texCoord2f (TexCoord2 0 0); vertex3f (Vertex3 (-2.0) (-1.0) 0.0 ) texCoord2f (TexCoord2 0 1); vertex3f (Vertex3 (-2.0) 1.0 0.0 ) texCoord2f (TexCoord2 1 1); vertex3f (Vertex3 0.0 1.0 0.0 ) texCoord2f (TexCoord2 1 0); vertex3f (Vertex3 0.0 (-1.0) 0.0 ) textureBinding Texture2D $= Just texName1 renderPrimitive Quads $ do texCoord2f (TexCoord2 0 0); vertex3f (Vertex3 1.0 (-1.0) 0.0 ) texCoord2f (TexCoord2 0 1); vertex3f (Vertex3 1.0 1.0 0.0 ) texCoord2f (TexCoord2 1 1); vertex3f (Vertex3 2.41421 1.0 (-1.41421)) texCoord2f (TexCoord2 1 0); vertex3f (Vertex3 2.41421 (-1.0) (-1.41421)) flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 60 (fromIntegral w / fromIntegral h) 1 30 matrixMode $= Modelview 0 loadIdentity translate (Vector3 0 0 (-3.6 :: GLfloat)) keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 250 250 initialWindowPosition $= Position 100 100 _ <- createWindow progName -- we have to do this *after* createWindow, otherwise we have no OpenGL context version <- get (majorMinor glVersion) when (version == (1,0)) $ do putStrLn "This program demonstrates a feature which is not in OpenGL Version 1.0." putStrLn "If your implementation of OpenGL Version 1.0 has the right extensions," putStrLn "you may be able to modify this program to make it run." exitFailure texNames <- myInit reshapeCallback $= Just reshape displayCallback $= display texNames keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/TessWind.hs0000644000000000000000000001512513255126367016247 0ustar0000000000000000{- TessWind.hs (adapted from tesswind.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates the winding rule polygon tessellation property. Four tessellated objects are drawn, each with very different contours. When the w key is pressed, the objects are drawn with a different winding rule. -} import Data.Char ( toLower ) import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { currentWindingRule :: IORef TessWinding } makeState :: IO State makeState = do c <- newIORef TessWindingOdd return $ State { currentWindingRule = c } type DisplayLists = (DisplayList, DisplayList, DisplayList, DisplayList) -- 'Float' is a dummy, any marshalable type would do type DontCare = Float rect1 :: ComplexContour DontCare rect1 = ComplexContour [ AnnotatedVertex (Vertex3 50 50 0) 0, AnnotatedVertex (Vertex3 300 50 0) 0, AnnotatedVertex (Vertex3 300 300 0) 0, AnnotatedVertex (Vertex3 50 300 0) 0 ] rect2 :: ComplexContour DontCare rect2 = ComplexContour [ AnnotatedVertex (Vertex3 100 100 0) 0, AnnotatedVertex (Vertex3 250 100 0) 0, AnnotatedVertex (Vertex3 250 250 0) 0, AnnotatedVertex (Vertex3 100 250 0) 0 ] rect3 :: ComplexContour DontCare rect3 = ComplexContour [ AnnotatedVertex (Vertex3 150 150 0) 0, AnnotatedVertex (Vertex3 200 150 0) 0, AnnotatedVertex (Vertex3 200 200 0) 0, AnnotatedVertex (Vertex3 150 200 0) 0 ] rects1 :: ComplexPolygon DontCare rects1 = ComplexPolygon [ rect1, rect2, rect3 ] rects2 :: ComplexPolygon DontCare rects2 = ComplexPolygon [ rect1, reverseComplexContour rect2, reverseComplexContour rect3 ] spiral :: ComplexPolygon DontCare spiral = ComplexPolygon [ ComplexContour [ AnnotatedVertex (Vertex3 400 250 0) 0, AnnotatedVertex (Vertex3 400 50 0) 0, AnnotatedVertex (Vertex3 50 50 0) 0, AnnotatedVertex (Vertex3 50 400 0) 0, AnnotatedVertex (Vertex3 350 400 0) 0, AnnotatedVertex (Vertex3 350 100 0) 0, AnnotatedVertex (Vertex3 100 100 0) 0, AnnotatedVertex (Vertex3 100 350 0) 0, AnnotatedVertex (Vertex3 300 350 0) 0, AnnotatedVertex (Vertex3 300 150 0) 0, AnnotatedVertex (Vertex3 150 150 0) 0, AnnotatedVertex (Vertex3 150 300 0) 0, AnnotatedVertex (Vertex3 250 300 0) 0, AnnotatedVertex (Vertex3 250 200 0) 0, AnnotatedVertex (Vertex3 200 200 0) 0, AnnotatedVertex (Vertex3 200 250 0) 0 ] ] quad1 :: ComplexContour DontCare quad1 = ComplexContour [ AnnotatedVertex (Vertex3 50 150 0) 0, AnnotatedVertex (Vertex3 350 150 0) 0, AnnotatedVertex (Vertex3 350 200 0) 0, AnnotatedVertex (Vertex3 50 200 0) 0 ] quad2 :: ComplexContour DontCare quad2 = ComplexContour [ AnnotatedVertex (Vertex3 100 100 0) 0, AnnotatedVertex (Vertex3 300 100 0) 0, AnnotatedVertex (Vertex3 300 350 0) 0, AnnotatedVertex (Vertex3 100 350 0) 0 ] tri :: ComplexContour DontCare tri = ComplexContour [ AnnotatedVertex (Vertex3 200 50 0) 0, AnnotatedVertex (Vertex3 250 300 0) 0, AnnotatedVertex (Vertex3 150 300 0) 0 ] quadsAndTri :: ComplexPolygon DontCare quadsAndTri = ComplexPolygon [ quad1, quad2, tri ] reverseComplexContour :: ComplexContour DontCare -> ComplexContour DontCare reverseComplexContour (ComplexContour avs) = ComplexContour (reverse avs) makeNewLists :: State -> DisplayLists -> IO () makeNewLists state (dl1, dl2, dl3, dl4) = do windingRule <- get (currentWindingRule state) print windingRule -- not in original program, but useful compileList windingRule dl1 rects1 compileList windingRule dl2 rects2 compileList windingRule dl3 spiral compileList windingRule dl4 quadsAndTri compileList :: TessWinding -> DisplayList -> ComplexPolygon DontCare -> IO () compileList windingRule displayList complexPolygon = defineList displayList Compile $ drawSimplePolygon =<< tessellate windingRule 0 (Normal3 0 0 0) noOpCombiner complexPolygon noOpCombiner :: Combiner DontCare noOpCombiner _newVertex _weightedProperties = 0 drawSimplePolygon :: SimplePolygon DontCare -> IO () drawSimplePolygon (SimplePolygon primitives) = flip mapM_ primitives $ \(Primitive primitiveMode vertices) -> renderPrimitive primitiveMode $ flip mapM_ vertices $ \(AnnotatedVertex plainVertex _) -> vertex plainVertex display :: DisplayLists -> DisplayCallback display (dl1, dl2, dl3, dl4) = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () translatef = translate :: Vector3 GLfloat -> IO () color3f (Color3 1 1 1) preservingMatrix $ do callList dl1 translatef (Vector3 0 500 0) callList dl2 translatef (Vector3 500 (-500) 0) callList dl3 translatef (Vector3 0 500 0) callList dl4 flush myInit :: State -> IO DisplayLists myInit state = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat [dl1, dl2, dl3, dl4] <- genObjectNames 4 let displayLists = (dl1, dl2, dl3, dl4) makeNewLists state displayLists return displayLists reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho2D 0 1000 0 (1000 * hf/wf) else ortho2D 0 (1000 * wf/hf) 0 1000 matrixMode $= Modelview 0 loadIdentity keyboard :: State -> DisplayLists -> KeyboardMouseCallback keyboard state displayLists (Char c) Down _ _ = case toLower c of 'w' -> do currentWindingRule state $~ nextWindingRule makeNewLists state displayLists postRedisplay Nothing '\27' -> exitWith ExitSuccess _ -> return () keyboard _ _ _ _ _ _ = return () nextWindingRule :: TessWinding -> TessWinding nextWindingRule r = case r of TessWindingOdd -> TessWindingNonzero TessWindingNonzero -> TessWindingPositive TessWindingPositive -> TessWindingNegative TessWindingNegative -> TessWindingAbsGeqTwo TessWindingAbsGeqTwo -> TessWindingOdd main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 500 500 _ <- createWindow progName state <- makeState displayLists <- myInit state displayCallback $= display displayLists reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard state displayLists) mainLoop GLUT-2.7.0.16/examples/RedBook4/Tess.hs0000644000000000000000000000762013255126367015426 0ustar0000000000000000{- Tess.hs (adapted from tess.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates polygon tessellation. Two tesselated objects are drawn. The first is a rectangle with a triangular hole. The second is a smooth shaded, self-intersecting star. Note the exterior rectangle is drawn with its vertices in counter-clockwise order, but its interior clockwise. Note the combineCallback is needed for the self-intersecting star. Also note that removing the TessProperty for the star will make the interior unshaded (TessWindingOdd). -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT display :: [DisplayList] -> DisplayCallback display displayLists = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () color3f (Color3 1 1 1) mapM_ callList displayLists flush -- 'Float' is a dummy, any marshalable type would do type DontCare = Float rectangle :: ComplexContour DontCare rectangle = ComplexContour [ AnnotatedVertex (Vertex3 50 50 0) 0, AnnotatedVertex (Vertex3 200 50 0) 0, AnnotatedVertex (Vertex3 200 200 0) 0, AnnotatedVertex (Vertex3 50 200 0) 0 ] tri :: ComplexContour DontCare tri = ComplexContour [ AnnotatedVertex (Vertex3 75 75 0) 0, AnnotatedVertex (Vertex3 125 175 0) 0, AnnotatedVertex (Vertex3 175 75 0) 0 ] rectAndTri :: ComplexPolygon DontCare rectAndTri = ComplexPolygon [ rectangle, tri ] noOpCombiner :: Combiner DontCare noOpCombiner _newVertex _weightedProperties = 0 star :: ComplexPolygon (Color3 GLfloat) star = ComplexPolygon [ ComplexContour [ AnnotatedVertex (Vertex3 250 50 0) (Color3 1 0 1), AnnotatedVertex (Vertex3 325 200 0) (Color3 1 1 0), AnnotatedVertex (Vertex3 400 50 0) (Color3 0 1 1), AnnotatedVertex (Vertex3 250 150 0) (Color3 1 0 0), AnnotatedVertex (Vertex3 400 150 0) (Color3 0 1 0) ] ] combineColors :: Combiner (Color3 GLfloat) combineColors _newVertex (WeightedProperties (w0, Color3 r0 g0 b0) (w1, Color3 r1 g1 b1) (w2, Color3 r2 g2 b2) (w3, Color3 r3 g3 b3)) = Color3 (w0*r0 + w1*r1 + w2*r2 + w3*r3) (w0*g0 + w1*g1 + w2*g2 + w3*g3) (w0*b0 + w1*b1 + w2*b2 + w3*b3) myInit :: IO [DisplayList] myInit = do clearColor $= Color4 0 0 0 0 rectAndTriList <- defineNewList Compile $ drawSimplePolygon (\_ -> return ()) =<< tessellate TessWindingOdd 0 (Normal3 0 0 0) noOpCombiner rectAndTri starList <- defineNewList Compile $ drawSimplePolygon color =<< tessellate TessWindingPositive 0 (Normal3 0 0 0) combineColors star return [ rectAndTriList, starList ] drawSimplePolygon :: (v -> IO ()) -> SimplePolygon v -> IO () drawSimplePolygon colorHandler (SimplePolygon primitives) = flip mapM_ primitives $ \(Primitive primitiveMode vertices) -> renderPrimitive primitiveMode $ flip mapM_ vertices $ \(AnnotatedVertex plainVertex col) -> do colorHandler col vertex plainVertex reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho2D 0 (fromIntegral w) 0 (fromIntegral h) matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 500 500 _ <- createWindow progName displayLists <- myInit displayCallback $= display displayLists reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/Teapots.hs0000644000000000000000000002157113255126367016130 0ustar0000000000000000{- Teapots.hs (adapted from teapots.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates lots of material properties. A single light source illuminates the objects. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT -- Initialize depth buffer, projection matrix, light source, and lighting -- model. Do not specify a material property here. myInit :: IO DisplayList myInit = do ambient (Light 0) $= Color4 0 0 0 1 diffuse (Light 0) $= Color4 1 1 1 1 position (Light 0) $= Vertex4 0 3 3 0 lightModelAmbient $= Color4 0.2 0.2 0.2 1 lightModelLocalViewer $= Disabled frontFace $= CW lighting $= Enabled light (Light 0) $= Enabled autoNormal $= Enabled normalize $= Enabled depthFunc $= Just Less -- be efficient--make teapot display list defineNewList Compile $ renderObject Solid (Teapot 1) -- Move object into position, specify the material properties, draw a teapot. renderTeapot :: DisplayList -> Vector3 GLfloat -> Color4 GLfloat -> Color4 GLfloat -> Color4 GLfloat -> GLfloat -> IO () renderTeapot teapotList pos amb dif spec shine = do preservingMatrix $ do translate pos materialAmbient Front $= amb materialDiffuse Front $= dif materialSpecular Front $= spec materialShininess Front $= shine * 128 callList teapotList -- 1st column: emerald, jade, obsidian, pearl, ruby, turquoise -- 2nd column: brass, bronze, chrome, copper, gold, silver -- 3rd column: black, cyan, green, red, white, yellow plastic -- 4th column: black, cyan, green, red, white, yellow rubber display :: DisplayList -> DisplayCallback display teapotList = do clear [ ColorBuffer, DepthBuffer ] renderTeapot teapotList (Vector3 2 17 0) (Color4 0.0215 0.1745 0.0215 1) (Color4 0.07568 0.61424 0.07568 1) (Color4 0.633 0.727811 0.633 1) 0.6 renderTeapot teapotList (Vector3 2 14 0) (Color4 0.135 0.2225 0.1575 1) (Color4 0.54 0.89 0.63 1) (Color4 0.316228 0.316228 0.316228 1) 0.1 renderTeapot teapotList (Vector3 2 11 0) (Color4 0.05375 0.05 0.06625 1) (Color4 0.18275 0.17 0.22525 1) (Color4 0.332741 0.328634 0.346435 1) 0.3 renderTeapot teapotList (Vector3 2 8 0) (Color4 0.25 0.20725 0.20725 1) (Color4 1 0.829 0.829 1) (Color4 0.296648 0.296648 0.296648 1) 0.088 renderTeapot teapotList (Vector3 2 5 0) (Color4 0.1745 0.01175 0.01175 1) (Color4 0.61424 0.04136 0.04136 1) (Color4 0.727811 0.626959 0.626959 1) 0.6 renderTeapot teapotList (Vector3 2 2 0) (Color4 0.1 0.18725 0.1745 1) (Color4 0.396 0.74151 0.69102 1) (Color4 0.297254 0.30829 0.306678 1) 0.1 renderTeapot teapotList (Vector3 6 17 0) (Color4 0.329412 0.223529 0.027451 1) (Color4 0.780392 0.568627 0.113725 1) (Color4 0.992157 0.941176 0.807843 1) 0.21794872 renderTeapot teapotList (Vector3 6 14 0) (Color4 0.2125 0.1275 0.054 1) (Color4 0.714 0.4284 0.18144 1) (Color4 0.393548 0.271906 0.166721 1) 0.2 renderTeapot teapotList (Vector3 6 11 0) (Color4 0.25 0.25 0.25 1) (Color4 0.4 0.4 0.4 1) (Color4 0.774597 0.774597 0.774597 1) 0.6 renderTeapot teapotList (Vector3 6 8 0) (Color4 0.19125 0.0735 0.0225 1) (Color4 0.7038 0.27048 0.0828 1) (Color4 0.256777 0.137622 0.086014 1) 0.1 renderTeapot teapotList (Vector3 6 5 0) (Color4 0.24725 0.1995 0.0745 1) (Color4 0.75164 0.60648 0.22648 1) (Color4 0.628281 0.555802 0.366065 1) 0.4 renderTeapot teapotList (Vector3 6 2 0) (Color4 0.19225 0.19225 0.19225 1) (Color4 0.50754 0.50754 0.50754 1) (Color4 0.508273 0.508273 0.508273 1) 0.4 renderTeapot teapotList (Vector3 10 17 0) (Color4 0 0 0 1) (Color4 0.01 0.01 0.01 1) (Color4 0.50 0.50 0.50 1) 0.25 renderTeapot teapotList (Vector3 10 14 0) (Color4 0 0.1 0.06 1) (Color4 0 0.50980392 0.50980392 1) (Color4 0.50196078 0.50196078 0.50196078 1) 0.25 renderTeapot teapotList (Vector3 10 11 0) (Color4 0 0 0 1) (Color4 0.1 0.35 0.1 1) (Color4 0.45 0.55 0.45 1) 0.25 renderTeapot teapotList (Vector3 10 8 0) (Color4 0 0 0 1) (Color4 0.5 0 0 1) (Color4 0.7 0.6 0.6 1) 0.25 renderTeapot teapotList (Vector3 10 5 0) (Color4 0 0 0 1) (Color4 0.55 0.55 0.55 1) (Color4 0.70 0.70 0.70 1) 0.25 renderTeapot teapotList (Vector3 10 2 0) (Color4 0 0 0 1) (Color4 0.5 0.5 0 1) (Color4 0.60 0.60 0.50 1) 0.25 renderTeapot teapotList (Vector3 14 17 0) (Color4 0.02 0.02 0.02 1) (Color4 0.01 0.01 0.01 1) (Color4 0.4 0.4 0.4 1) 0.078125 renderTeapot teapotList (Vector3 14 14 0) (Color4 0 0.05 0.05 1) (Color4 0.4 0.5 0.5 1) (Color4 0.04 0.7 0.7 1) 0.078125 renderTeapot teapotList (Vector3 14 11 0) (Color4 0 0.05 0 1) (Color4 0.4 0.5 0.4 1) (Color4 0.04 0.7 0.04 1) 0.078125 renderTeapot teapotList (Vector3 14 8 0) (Color4 0.05 0 0 1) (Color4 0.5 0.4 0.4 1) (Color4 0.7 0.04 0.04 1) 0.078125 renderTeapot teapotList (Vector3 14 5 0) (Color4 0.05 0.05 0.05 1) (Color4 0.5 0.5 0.5 1) (Color4 0.7 0.7 0.7 1) 0.078125 renderTeapot teapotList (Vector3 14 2 0) (Color4 0.05 0.05 0 1) (Color4 0.5 0.5 0.4 1) (Color4 0.7 0.7 0.04 1) 0.078125 flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho 0 16 0 (16 * hf/wf) (-10) 10 else ortho 0 (16 * wf/hf) 0 16 (-10) 10 matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 500 600 initialWindowPosition $= Position 50 50 _ <- createWindow progName teapotList <- myInit reshapeCallback $= Just reshape displayCallback $= display teapotList keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/Surface.hs0000644000000000000000000000674213255126367016104 0ustar0000000000000000{- Surface.hs (adapted from surface.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program draws a NURBS surface in the shape of a symmetrical hill. The 'c' keyboard key allows you to toggle the visibility of the control points themselves. Note that some of the control points are hidden by the surface itself. NOTE: This example does NOT demonstrate the final NURBS API, it's currently just a test for the internals... -} import Control.Monad ( when ) import Data.Char ( toLower ) import Data.IORef ( IORef, newIORef ) import Foreign.Marshal ( withArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { showPoints :: IORef Bool } makeState :: IO State makeState = do s <- newIORef False return $ State { showPoints = s } -- The control points of the surface form a small hill and -- range from -3 to +3 in x, y, and z. ctlPoints :: [[Vertex3 GLfloat]] ctlPoints = [ [ Vertex3 (2 * u - 3) (2 * v - 3) (if (u == 1 || u ==2) && (v == 1 || v == 2) then 3 else -3) | v <- [ 0 .. 3 ] ] | u <- [ 0 .. 3 ]] myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 materialDiffuse Front $= Color4 0.7 0.7 0.7 1 materialSpecular Front $= Color4 1 1 1 1 materialShininess Front $= 100 lighting $= Enabled light (Light 0) $= Enabled depthFunc $= Just Less autoNormal $= Enabled normalize $= Enabled -------------------------------------------------------------------------------- display :: State -> DisplayCallback display state = do let knots = [ 0, 0, 0, 0, 1, 1, 1, 1 ] :: [GLfloat] clear [ ColorBuffer, DepthBuffer ] preservingMatrix $ do rotate (330 :: GLfloat) (Vector3 1 0 0) scale 0.5 0.5 (0.5 :: GLfloat) withNURBSObj () $ \nurbsObj -> do setSamplingMethod nurbsObj (PathLength 25) setDisplayMode' nurbsObj Fill' checkForNURBSError nurbsObj $ nurbsBeginEndSurface nurbsObj $ withArray (concat ctlPoints) $ \cBuf -> withArray knots $ \kBuf -> nurbsSurface nurbsObj 8 kBuf 8 kBuf (4 * 3) 3 cBuf 4 4 s <- get (showPoints state) when s $ do pointSize $= 5 lighting $= Disabled color (Color3 1 1 (0 :: GLfloat)) renderPrimitive Points $ mapM_ (mapM_ vertex) ctlPoints lighting $= Enabled flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 45 (fromIntegral w / fromIntegral h) 3 8 matrixMode $= Modelview 0 loadIdentity translate (Vector3 0 0 (-5 :: GLfloat)) keyboard :: State -> KeyboardMouseCallback keyboard state (Char c) Down _ _ = case toLower c of 'c' -> do showPoints state $~ not; postRedisplay Nothing '\27' -> exitWith ExitSuccess _ -> return () keyboard _ _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName state <- makeState myInit reshapeCallback $= Just reshape displayCallback $= display state keyboardMouseCallback $= Just (keyboard state) mainLoop GLUT-2.7.0.16/examples/RedBook4/SurfPoints.hs0000644000000000000000000001065113255126367016622 0ustar0000000000000000{- SurfPoints.hs (adapted from surfpoints.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program is a modification of the earlier Surface.hs program. The vertex data are not directly rendered, but are instead passed to the callback function. The values of the tessellated vertices are printed out there. This program draws a NURBS surface in the shape of a symmetrical hill. The 'c' keyboard key allows you to toggle the visibility of the control points themselves. Note that some of the control points are hidden by the surface itself. NOTE: This example does NOT demonstrate the final NURBS API, it's currently just a test for the internals... -} import Control.Monad ( when ) import Data.Char ( toLower ) import Data.IORef ( IORef, newIORef ) import Foreign.Marshal ( withArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { showPoints :: IORef Bool } makeState :: IO State makeState = do s <- newIORef False return $ State { showPoints = s } -- The control points of the surface form a small hill and -- range from -3 to +3 in x, y, and z. ctlPoints :: [[Vertex3 GLfloat]] ctlPoints = [ [ Vertex3 (2 * u - 3) (2 * v - 3) (if (u == 1 || u ==2) && (v == 1 || v == 2) then 3 else -3) | v <- [ 0 .. 3 ] ] | u <- [ 0 .. 3 ]] myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 materialDiffuse Front $= Color4 0.7 0.7 0.7 1 materialSpecular Front $= Color4 1 1 1 1 materialShininess Front $= 100 lighting $= Enabled light (Light 0) $= Enabled depthFunc $= Just Less autoNormal $= Enabled normalize $= Enabled -------------------------------------------------------------------------------- display :: State -> DisplayCallback display state = do let knots = [ 0, 0, 0, 0, 1, 1, 1, 1 ] :: [GLfloat] clear [ ColorBuffer, DepthBuffer ] preservingMatrix $ do rotate (330 :: GLfloat) (Vector3 1 0 0) scale 0.5 0.5 (0.5 :: GLfloat) withNURBSObj () $ \nurbsObj -> do setNURBSMode nurbsObj NURBSTessellator setSamplingMethod nurbsObj (PathLength 25) setDisplayMode' nurbsObj Fill' checkForNURBSError nurbsObj $ withNURBSBeginCallback nurbsObj print $ withNURBSVertexCallback nurbsObj print $ withNURBSNormalCallback nurbsObj print $ withNURBSEndCallback nurbsObj (putStrLn "end") $ nurbsBeginEndSurface nurbsObj $ withArray (concat ctlPoints) $ \cBuf -> withArray knots $ \kBuf -> nurbsSurface nurbsObj 8 kBuf 8 kBuf (4 * 3) 3 cBuf 4 4 s <- get (showPoints state) when s $ do pointSize $= 5 lighting $= Disabled color (Color3 1 1 (0 :: GLfloat)) renderPrimitive Points $ mapM_ (mapM_ vertex) ctlPoints lighting $= Enabled flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 45 (fromIntegral w / fromIntegral h) 3 8 matrixMode $= Modelview 0 loadIdentity translate (Vector3 0 0 (-5 :: GLfloat)) keyboard :: State -> KeyboardMouseCallback keyboard state (Char c) Down _ _ = case toLower c of 'c' -> do showPoints state $~ not; postRedisplay Nothing '\27' -> exitWith ExitSuccess _ -> return () keyboard _ _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName version <- get (majorMinor gluVersion) when (version < (1,3)) $ do putStrLn "This program demonstrates a feature which is introduced in the" putStrLn "OpenGL Utility Library (GLU) Version 1.3." putStrLn "If your implementation of GLU has the right extensions," putStrLn "you may be able to modify this program to make it run." putStrLn "Continuing anyway..." state <- makeState myInit reshapeCallback $= Just reshape displayCallback $= display state keyboardMouseCallback $= Just (keyboard state) mainLoop GLUT-2.7.0.16/examples/RedBook4/Stroke.hs0000644000000000000000000000754213255126367015762 0ustar0000000000000000{- Stroke.hs (adapted from stroke.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates some characters of a stroke (vector) font. The characters are represented by display lists, which are given numbers which correspond to the ASCII values of the characters. Use of callLists is demonstrated. -} import Data.List ( genericLength ) import Foreign.C.String ( castCharToCChar ) import Foreign.Marshal.Array ( withArray ) import Graphics.UI.GLUT import System.Exit ( exitWith, ExitCode(ExitSuccess) ) aData, eData, pData, rData, sData :: [[Vertex2 GLfloat]] aData = [ [ Vertex2 0 0, Vertex2 0 9, Vertex2 1 10, Vertex2 4 10, Vertex2 5 9, Vertex2 5 0 ], [ Vertex2 0 5, Vertex2 5 5 ] ] eData = [ [ Vertex2 5 0, Vertex2 0 0, Vertex2 0 10, Vertex2 5 10 ], [ Vertex2 0 5, Vertex2 4 5 ] ] pData = [ [ Vertex2 0 0, Vertex2 0 10, Vertex2 4 10, Vertex2 5 9, Vertex2 5 6, Vertex2 4 5, Vertex2 0 5 ] ] rData = [ [ Vertex2 0 0, Vertex2 0 10, Vertex2 4 10, Vertex2 5 9, Vertex2 5 6, Vertex2 4 5, Vertex2 0 5 ], [ Vertex2 3 5, Vertex2 5 0 ] ] sData = [ [ Vertex2 0 1, Vertex2 1 0, Vertex2 4 0, Vertex2 5 1, Vertex2 5 4, Vertex2 4 5, Vertex2 1 5, Vertex2 0 6, Vertex2 0 9, Vertex2 1 10, Vertex2 4 10, Vertex2 5 9 ] ] advance :: IO () advance = translate (Vector3 8 0 (0 :: GLfloat)) -- drawLetter renders a letter with line segments given by the list of line -- strips. drawLetter :: [[Vertex2 GLfloat]] -> IO () drawLetter lineStrips = do mapM_ (renderPrimitive LineStrip . mapM_ vertex) lineStrips advance charToGLubyte :: Char -> GLubyte charToGLubyte = fromIntegral . castCharToCChar myInit :: IO () myInit = do shadeModel $= Flat (base@(DisplayList b):_) <- genObjectNames 128 listBase $= base let charToDisplayList c = DisplayList (b + fromIntegral (charToGLubyte c)) mapM_ (\(c, d) -> defineList (charToDisplayList c) Compile d) [ ('A', drawLetter aData), ('E', drawLetter eData), ('P', drawLetter pData), ('R', drawLetter rData), ('S', drawLetter sData), (' ', advance) ] test1, test2 :: String test1 = "A SPARE SERAPE APPEARS AS" test2 = "APES PREPARE RARE PEPPERS" printStrokedString :: String -> IO () printStrokedString s = withArray (map charToGLubyte s) $ callLists (genericLength s) UnsignedByte display :: DisplayCallback display = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () scalef = scale :: GLfloat -> GLfloat -> GLfloat -> IO () translatef = translate :: Vector3 GLfloat -> IO () color3f (Color3 1 1 1) preservingMatrix $ do scalef 2 2 2 translatef (Vector3 10 30 0) printStrokedString test1 preservingMatrix $ do scalef 2 2 2 translatef (Vector3 10 13 0) printStrokedString test2 flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho2D 0 (fromIntegral w) 0 (fromIntegral h) matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char c) Down _ _ = case c of ' ' -> postRedisplay Nothing '\27' -> exitWith ExitSuccess _ -> return () keyboard _ _ _ _ = return () -- Main Loop: Open window with initial window size, title bar, RGBA display -- mode, and handle input events. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 440 120 _ <- createWindow progName myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard displayCallback $= display mainLoop GLUT-2.7.0.16/examples/RedBook4/Stencil.hs0000644000000000000000000000761313255126367016113 0ustar0000000000000000{- Stencil.hs (adapted from stencil.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates use of the stencil buffer for masking nonrectangular regions. Whenever the window is redrawn, a value of 1 is drawn into a diamond-shaped region in the stencil buffer. Elsewhere in the stencil buffer, the value is 0. Then a blue sphere is drawn where the stencil value is 1, and yellow torii are drawn where the stencil value is not 1. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data DisplayLists = DisplayLists { yellowMat, blueMat :: DisplayList } myInit :: IO DisplayLists myInit = do y <- defineNewList Compile $ do materialDiffuse Front $= Color4 0.7 0.7 0 1 materialSpecular Front $= Color4 1 1 1 1 materialShininess Front $= 64 b <- defineNewList Compile $ do materialDiffuse Front $= Color4 0.1 0.1 0.7 1 materialSpecular Front $= Color4 0.1 1 1 1 materialShininess Front $= 45 position (Light 0) $= Vertex4 1 1 1 0 light (Light 0) $= Enabled lighting $= Enabled depthFunc $= Just Less clearStencil $= 0 stencilTest $= Enabled return $ DisplayLists { yellowMat = y, blueMat = b } -- Draw a sphere in a diamond-shaped section in the middle of a window with 2 -- torii. display :: DisplayLists -> DisplayCallback display displayLists = do clear [ ColorBuffer, DepthBuffer ] -- draw blue sphere where the stencil is 1 stencilFunc $= (Equal, 1, 1) stencilOp $= (OpKeep, OpKeep, OpKeep) callList (blueMat displayLists) renderObject Solid (Sphere' 0.5 15 15) -- resolve overloading, not needed in "real" programs let rotatef = rotate :: GLfloat -> Vector3 GLfloat -> IO () -- draw the tori where the stencil is not 1 stencilFunc $= (Notequal, 1, 1) preservingMatrix $ do rotatef 45 (Vector3 0 0 1) rotatef 45 (Vector3 0 1 0) callList (yellowMat displayLists) renderObject Solid (Torus 0.275 0.85 15 15) preservingMatrix $ do rotatef 90 (Vector3 1 0 0) renderObject Solid (Torus 0.275 0.85 15 15) flush -- Whenever the window is reshaped, redefine the coordinate system and redraw -- the stencil area. reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) -- create a diamond shaped stencil area matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho2D (-3) 3 (-3*hf/wf) (3*hf/wf) else ortho2D (-3*wf/hf) (3*wf/hf) (-3) 3 matrixMode $= Modelview 0 loadIdentity -- resolve overloading, not needed in "real" programs let vertex2f = vertex :: Vertex2 GLfloat -> IO () translatef = translate :: Vector3 GLfloat -> IO () clear [ StencilBuffer ] stencilFunc $= (Always, 1, 1) stencilOp $= (OpReplace, OpReplace, OpReplace) renderPrimitive Quads $ do vertex2f (Vertex2 (-1) 0) vertex2f (Vertex2 0 1) vertex2f (Vertex2 1 0) vertex2f (Vertex2 0 (-1)) matrixMode $= Projection loadIdentity perspective 45 (wf/hf) 3 7 matrixMode $= Modelview 0 loadIdentity translatef (Vector3 0 0 (-5)) keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () -- Main Loop: Be certain to request stencil bits. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer, WithStencilBuffer ] initialWindowSize $= Size 400 400 initialWindowPosition $= Position 100 100 _ <- createWindow progName displayLists <- myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard displayCallback $= display displayLists mainLoop GLUT-2.7.0.16/examples/RedBook4/Smooth.hs0000644000000000000000000000343113255126367015755 0ustar0000000000000000{- Smooth.hs (adapted from smooth.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates smooth shading. A smooth shaded polygon is drawn in a 2-D projection. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Smooth triangle :: IO () triangle = -- resolve overloading, not needed in "real" programs let vertex2f = vertex :: Vertex2 GLfloat -> IO () color3f = color :: Color3 GLfloat -> IO () in renderPrimitive Triangles $ do color3f (Color3 1 0 0) vertex2f (Vertex2 5 5) color3f (Color3 0 1 0) vertex2f (Vertex2 25 5) color3f (Color3 0 0 1) vertex2f (Vertex2 5 25) display :: DisplayCallback display = do clear [ ColorBuffer ] triangle flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho2D 0 30 0 (30 * hf/wf) else ortho2D 0 (30 * wf/hf) 0 30 matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit displayCallback $= display reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/ShadowMap.hs0000644000000000000000000002017713255126367016375 0ustar0000000000000000{- ShadowMap.hs (adapted from shadowmap.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE -} import Control.Monad ( when, unless ) import Data.IORef ( IORef, newIORef ) import Foreign.Marshal.Array ( allocaArray ) import Foreign.Ptr ( nullPtr ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT shadowMapSize :: TextureSize2D shadowMapSize = TextureSize2D 256 256 fovy, nearPlane, farPlane :: GLdouble fovy = 60 nearPlane = 10 farPlane = 100 lightPos :: Vertex4 GLfloat lightPos = Vertex4 25 25 25 1 lookat :: Vertex3 GLdouble lookat = Vertex3 0 0 0 up :: Vector3 GLdouble up = Vector3 0 0 1 data State = State { angle :: IORef GLdouble, torusAngle :: IORef GLfloat, showShadow :: IORef Bool, animate :: IORef Bool, funcMode :: IORef ComparisonFunction } makeState :: IO State makeState = do a <- newIORef 0 t <- newIORef 0 s <- newIORef False n <- newIORef True f <- newIORef Lequal return $ State { angle = a, torusAngle = t, showShadow = s, animate = n, funcMode = f } myInit :: IO () myInit = do texImage2D Texture2D NoProxy 0 DepthComponent' shadowMapSize 0 (PixelData DepthComponent UnsignedByte nullPtr) position (Light 0) $= lightPos let white = Color4 1 1 1 1 specular (Light 0) $= white diffuse (Light 0) $= white textureWrapMode Texture2D S $= (Repeated, ClampToEdge) textureWrapMode Texture2D T $= (Repeated, ClampToEdge) textureFilter Texture2D $= ((Linear', Nothing), Linear') textureCompareMode Texture2D $= Just Lequal depthTextureMode Texture2D $= Luminance' colorMaterial $= Just (FrontAndBack, AmbientAndDiffuse) cullFace $= Just Back depthFunc $= Just Less light (Light 0) $= Enabled lighting $= Enabled texture Texture2D $= Enabled reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective fovy (fromIntegral w / fromIntegral h) nearPlane farPlane matrixMode $= Modelview 0 idle :: State -> IdleCallback idle state = do angle state $~! (+ (pi / 10000)) torusAngle state $~! (+ 0.1) postRedisplay Nothing keyboard :: State -> KeyboardMouseCallback keyboard state (Char c) Down _ _ = do case c of '\27' -> exitWith ExitSuccess 't' -> texture Texture2D $~ \cap -> if cap == Enabled then Disabled else Enabled 'm' -> do fm <- get (funcMode state) textureCompareMode Texture2D $~ maybe (Just fm) (const Nothing) compareMode <- get (textureCompareMode Texture2D) putStrLn ("Compare mode " ++ maybe "Off" (const "On") compareMode) 'f' -> do funcMode state $~ \fm -> if fm == Lequal then Gequal else Lequal fm <- get (funcMode state) putStrLn ("Operator " ++ show fm) textureCompareMode Texture2D $~ maybe Nothing (const (Just fm)) 's' -> showShadow state $~ not 'p' -> do animate state $~ not animate' <- get (animate state) idleCallback $= if animate' then Just (idle state) else Nothing _ -> return () postRedisplay Nothing keyboard _ _ _ _ _ = return () drawObjects :: GLfloat -> Bool -> IO () drawObjects torusAngle' shadowRender = do textureOn <- get (texture Texture2D) when shadowRender $ texture Texture2D $= Disabled -- resolve overloading, not needed in "real" programs let normal3f = normal :: Normal3 GLfloat -> IO () color3f = color :: Color3 GLfloat -> IO () rectf = rect :: Vertex2 GLfloat -> Vertex2 GLfloat -> IO () translatef = translate :: Vector3 GLfloat -> IO () rotatef = rotate :: GLfloat -> Vector3 GLfloat -> IO () unless shadowRender $ do normal3f (Normal3 0 0 1) color3f (Color3 1 1 1) rectf (Vertex2 (-20) (-20)) (Vertex2 20 20) preservingMatrix $ do translatef (Vector3 11 11 11) rotatef 54.73 (Vector3 (-5) 5 0) rotate torusAngle' (Vector3 1 0 0) color3f (Color3 1 0 0) renderObject Solid (Torus 1 4 8 36) preservingMatrix $ do translatef (Vector3 2 2 2) color3f (Color3 0 0 1) renderObject Solid (Cube 4) preservingMatrix $ do getLightPos Vector3 >>= translate color3f (Color3 1 1 1) renderObject Wireframe (Sphere' 0.5 6 6) when (shadowRender && textureOn == Enabled) $ texture Texture2D $= Enabled getLightPos :: (GLdouble -> GLdouble -> GLdouble -> a) -> IO a getLightPos f = do Vertex4 x y z _ <- get (position (Light 0)) return $ f (realToFrac x) (realToFrac y) (realToFrac z) generateShadowMap :: GLfloat -> Bool -> IO () generateShadowMap torusAngle' showShadow' = do lightPos' <- getLightPos Vertex3 let (TextureSize2D shadowMapWidth shadowMapHeight) = shadowMapSize shadowMapSize' = Size shadowMapWidth shadowMapHeight preservingViewport $ do viewport $= (Position 0 0, shadowMapSize') clear [ ColorBuffer, DepthBuffer ] matrixMode $= Projection preservingMatrix $ do loadIdentity perspective 80 1 10 1000 matrixMode $= Modelview 0 preservingMatrix $ do loadIdentity lookAt lightPos' lookat up drawObjects torusAngle' True matrixMode $= Projection matrixMode $= Modelview 0 copyTexImage2D Texture2D 0 DepthComponent' (Position 0 0) shadowMapSize 0 when showShadow' $ do let numShadowMapPixels = fromIntegral (shadowMapWidth * shadowMapHeight) allocaArray numShadowMapPixels $ \depthImage -> do let pixelData fmt = PixelData fmt Float depthImage :: PixelData GLfloat readPixels (Position 0 0) shadowMapSize' (pixelData DepthComponent) (_, Size viewPortWidth _) <- get viewport windowPos (Vertex2 (fromIntegral viewPortWidth / 2 :: GLfloat) 0) drawPixels shadowMapSize' (pixelData Luminance) swapBuffers -- Note: preservingViewport is not exception safe, but it doesn't matter here preservingViewport :: IO a -> IO a preservingViewport act = do v <- get viewport x <- act viewport $= v return x generateTextureMatrix :: IO () generateTextureMatrix = do -- Set up projective texture matrix. We use the Modelview matrix stack and -- OpenGL matrix commands to make the matrix. m <- preservingMatrix $ do loadIdentity -- resolve overloading, not needed in "real" programs let translatef = translate :: Vector3 GLfloat -> IO () scalef = scale :: GLfloat -> GLfloat -> GLfloat -> IO () translatef (Vector3 0.5 0.5 0.0) scalef 0.5 0.5 1.0 perspective 60 1 1 1000 lightPos' <- getLightPos Vertex3 lookAt lightPos' lookat up get (matrix (Just (Modelview 0))) [ sx, sy, sz, sw, tx, ty, tz, tw, rx, ry, rz, rw, qx, qy, qz, qw ] <- getMatrixComponents RowMajor (m :: GLmatrix GLdouble) textureGenMode S $= Just (ObjectLinear (Plane sx sy sz sw)) textureGenMode T $= Just (ObjectLinear (Plane tx ty tz tw)) textureGenMode R $= Just (ObjectLinear (Plane rx ry rz rw)) textureGenMode Q $= Just (ObjectLinear (Plane qx qy qz qw)) display :: State -> DisplayCallback display state = do let radius = 30 torusAngle' <- get (torusAngle state) showShadow' <- get (showShadow state) generateShadowMap torusAngle' showShadow' generateTextureMatrix unless showShadow' $ do clear [ ColorBuffer, DepthBuffer ] preservingMatrix $ do angle' <- get (angle state) lookAt (Vertex3 (radius * cos angle') (radius * sin angle') 30) lookat up drawObjects torusAngle' False swapBuffers main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ RGBAMode, WithDepthBuffer, DoubleBuffered ] initialWindowSize $= Size 521 512 initialWindowPosition $= Position 100 100 _ <- createWindow progName state <- makeState myInit displayCallback $= display state reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard state) idleCallback $= Just (idle state) mainLoop GLUT-2.7.0.16/examples/RedBook4/Select.hs0000644000000000000000000001245213255126367015726 0ustar0000000000000000{- Select.hs (adapted from select.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This is an illustration of the selection mode and name stack, which detects whether objects which collide with a viewing volume. First, four triangles and a rectangular box representing a viewing volume are drawn (drawScene routine). The green triangle and yellow triangles appear to lie within the viewing volume, but the red triangle appears to lie outside it. Then the selection mode is entered (selectObjects routine). Drawing to the screen ceases. To see if any collisions occur, the four triangles are called. In this example, the green triangle causes one hit with the name 1, and the yellow triangles cause one hit with the name 3. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT -- draw a triangle with vertices at (x1, y1), (x2, y2) and (x3, y3) at z units -- away from the origin. drawTriangle :: Vertex2 GLfloat -> Vertex2 GLfloat -> Vertex2 GLfloat -> GLfloat -> IO () drawTriangle (Vertex2 x1 y1) (Vertex2 x2 y2) (Vertex2 x3 y3) z = do renderPrimitive Triangles $ mapM_ vertex [ Vertex3 x1 y1 z, Vertex3 x2 y2 z, Vertex3 x3 y3 z] -- draw a rectangular box with these outer x, y, and z values drawViewVolume :: Vertex3 GLfloat -> Vertex3 GLfloat -> IO () drawViewVolume (Vertex3 x1 y1 z1) (Vertex3 x2 y2 z2) = do -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () color3f (Color3 1 1 1) renderPrimitive LineLoop $ mapM_ vertex [ Vertex3 x1 y1 (-z1), Vertex3 x2 y1 (-z1), Vertex3 x2 y2 (-z1), Vertex3 x1 y2 (-z1)] renderPrimitive LineLoop $ mapM_ vertex [ Vertex3 x1 y1 (-z2), Vertex3 x2 y1 (-z2), Vertex3 x2 y2 (-z2), Vertex3 x1 y2 (-z2)] renderPrimitive Lines $ mapM_ vertex [ -- 4 lines Vertex3 x1 y1 (-z1), Vertex3 x1 y1 (-z2), Vertex3 x1 y2 (-z1), Vertex3 x1 y2 (-z2), Vertex3 x2 y1 (-z1), Vertex3 x2 y1 (-z2), Vertex3 x2 y2 (-z1), Vertex3 x2 y2 (-z2)] -- drawScene draws 4 triangles and a wire frame which represents the viewing -- volume. drawScene :: IO () drawScene = do matrixMode $= Projection loadIdentity perspective 40 (4/3) 1 100 matrixMode $= Modelview 0 loadIdentity lookAt (Vertex3 7.5 7.5 12.5) (Vertex3 2.5 2.5 (-5)) (Vector3 0 1 0) -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () color3f (Color3 0 1 0) -- green triangle drawTriangle (Vertex2 2 2) (Vertex2 3 2) (Vertex2 2.5 3) (-5) color3f (Color3 1 0 0) -- red triangle drawTriangle (Vertex2 2 7) (Vertex2 3 7) (Vertex2 2.5 8) (-5) color3f (Color3 1 1 0) -- yellow triangles drawTriangle (Vertex2 2 2) (Vertex2 3 2) (Vertex2 2.5 3) (-1) drawTriangle (Vertex2 2 2) (Vertex2 3 2) (Vertex2 2.5 3) (-9) drawViewVolume (Vertex3 0 0 0) (Vertex3 5 5 10) processHits :: Maybe [HitRecord] -> IO () processHits Nothing = putStrLn "selection buffer overflow" processHits (Just hitRecords) = do putStrLn ("hits = " ++ show (length hitRecords)) mapM_ (\(HitRecord z1 z2 names) -> do putStrLn (" number of names for hit = " ++ show (length names)) putStr (" z1 is " ++ show z1) putStrLn ("; z2 is " ++ show z2) putStr " the name is" sequence_ [ putStr (" " ++ show n) | Name n <- names ] putChar '\n') hitRecords -- selectObjects "draws" the triangles in selection mode, assigning names for -- the triangles. Note that the third and fourth triangles share one name, so -- that if either or both triangles intersects the viewing/clipping volume, -- only one hit will be registered. bufSize :: GLsizei bufSize = 512 selectObjects :: IO () selectObjects = do (_, maybeHitRecords) <- getHitRecords bufSize $ do withName (Name 0) $ do preservingMatrix $ do matrixMode $= Projection loadIdentity ortho 0 5 0 5 0 10 matrixMode $= Modelview 0 loadIdentity loadName (Name 1) drawTriangle (Vertex2 2 2) (Vertex2 3 2) (Vertex2 2.5 3) (-5) loadName (Name 2) drawTriangle (Vertex2 2 7) (Vertex2 3 7) (Vertex2 2.5 8) (-5) loadName (Name 3) drawTriangle (Vertex2 2 2) (Vertex2 3 2) (Vertex2 2.5 3) (-1) drawTriangle (Vertex2 2 2) (Vertex2 3 2) (Vertex2 2.5 3) (-9) flush processHits maybeHitRecords myInit :: IO () myInit = do depthFunc $= Just Less shadeModel $= Flat display :: DisplayCallback display = do clearColor $= Color4 0 0 0 0 clear [ ColorBuffer, DepthBuffer ] drawScene selectObjects flush keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () -- Main Loop main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 200 200 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit displayCallback $= display keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/Scene.hs0000644000000000000000000000447313255126367015550 0ustar0000000000000000{- Scene.hs (adapted from scene.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates the use of the GL lighting model. Objects are drawn using a grey material characteristic. A single light source illuminates the objects. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT -- Initialize material property and light source. myInit :: IO () myInit = do ambient (Light 0) $= Color4 0 0 0 1 diffuse (Light 0) $= Color4 1 1 1 1 specular (Light 0) $= Color4 1 1 1 1 -- light position is NOT default value position (Light 0) $= Vertex4 1 1 1 0 lighting $= Enabled light (Light 0) $= Enabled depthFunc $= Just Less display :: DisplayCallback display = do clear [ ColorBuffer, DepthBuffer ] preservingMatrix $ do rotate (20 :: GLfloat) (Vector3 1 0 0) preservingMatrix $ do translate (Vector3 (-0.75) 0.5 (0 :: GLfloat)) rotate (90 :: GLfloat) (Vector3 1 0 0) renderObject Solid (Torus 0.275 0.85 15 15) preservingMatrix $ do translate (Vector3 (-0.75) (-0.5) (0 :: GLfloat)) rotate (270 :: GLfloat) (Vector3 1 0 0) renderObject Solid (Cone 1 2 15 15) preservingMatrix $ do translate (Vector3 0.75 0 (-1 :: GLfloat)) renderObject Solid (Sphere' 1 15 15) flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho (-2.5) 2.5 (-2.5 * hf/wf) (2.5 * hf/wf) (-10) 10 else ortho (-2.5 * wf/hf) (2.5 * wf/hf) (-2.5) 2.5 (-10) 10 matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 500 500 _ <- createWindow progName myInit reshapeCallback $= Just reshape displayCallback $= display keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/Robot.hs0000644000000000000000000000544213255126367015575 0ustar0000000000000000{- Robot.hs (adapted from robot.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program shows how to composite modeling transformations to draw translated and rotated hierarchical models. Interaction: pressing the s and e keys (shoulder and elbow) alters the rotation of the robot arm. -} import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { shoulder, elbow :: IORef GLint } makeState :: IO State makeState = do s <- newIORef 0 e <- newIORef 0 return $ State { shoulder = s, elbow = e } myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat display :: State -> DisplayCallback display state = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let translatef = translate :: Vector3 GLfloat -> IO () scalef = scale :: GLfloat -> GLfloat -> GLfloat -> IO () preservingMatrix $ do translatef (Vector3 (-1) 0 0) s <- get (shoulder state) rotate (fromIntegral s :: GLfloat) (Vector3 0 0 1) translatef (Vector3 1 0 0) preservingMatrix $ do scalef 2 0.4 1 renderObject Wireframe (Cube 1) translatef (Vector3 1 0 0) e <- get (elbow state) rotate (fromIntegral e :: GLfloat) (Vector3 0 0 1) translatef (Vector3 1 0 0) preservingMatrix $ do scalef 2 0.4 1 renderObject Wireframe (Cube 1) swapBuffers reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 65 (fromIntegral w / fromIntegral h) 1 20 matrixMode $= Modelview 0 loadIdentity -- resolve overloading, not needed in "real" programs let translatef = translate :: Vector3 GLfloat -> IO () translatef (Vector3 0 0 (-5)) keyboard :: State -> KeyboardMouseCallback keyboard state (Char c) Down _ _ = case c of 's' -> update shoulder 5 'S' -> update shoulder (-5) 'e' -> update elbow 5 'E' -> update elbow (-5) '\27' -> exitWith ExitSuccess _ -> return () where update joint inc = do joint state $~ ((`mod` 360) . (+ inc)) postRedisplay Nothing keyboard _ _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ DoubleBuffered, RGBMode ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName state <- makeState myInit displayCallback $= display state reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard state) mainLoop GLUT-2.7.0.16/examples/RedBook4/Quadric.hs0000644000000000000000000000671413255126367016103 0ustar0000000000000000{- Quadric.hs (adapted from quadric.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates the use of the renderQuadric routine. Quadric objects are created with some quadric properties and errors are reported. Note that the cylinder has no top or bottom and the circle has a hole in it. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT myInit :: IO (DisplayList, DisplayList, DisplayList, DisplayList) myInit = do clearColor $= Color4 0 0 0 0 materialAmbient Front $= Color4 0.5 0.5 0.5 1 materialSpecular Front $= Color4 1 1 1 1 materialShininess Front $= 50 position (Light 0) $= Vertex4 1 1 1 0 lightModelAmbient $= Color4 0.5 0.5 0.5 1 lighting $= Enabled light (Light 0) $= Enabled depthFunc $= Just Less -- Create 4 display lists, each with a different quadric object. -- Different drawing styles and surface normal specifications -- are demonstrated. -- smooth shaded dl1 <- newQuadricDL (Just Smooth) FillStyle (Sphere 0.75 15 10) -- flat shaded dl2 <- newQuadricDL (Just Flat) FillStyle (Cylinder 0.5 0.3 1 15 5) -- all polygons wireframe dl3 <- newQuadricDL Nothing LineStyle (Disk 0.25 1 20 4) -- boundary only dl4 <- newQuadricDL Nothing SilhouetteStyle (PartialDisk 0 1 20 4 0 225) return (dl1, dl2, dl3, dl4) newQuadricDL :: QuadricNormal -> QuadricDrawStyle -> QuadricPrimitive -> IO DisplayList newQuadricDL n s p = defineNewList Compile $ do renderQuadric (QuadricStyle n NoTextureCoordinates Outside s) p reportErrors display :: (DisplayList, DisplayList, DisplayList, DisplayList) -> DisplayCallback display (dl1, dl2, dl3, dl4) = do clear [ ColorBuffer, DepthBuffer ] preservingMatrix $ do -- resolve overloading, not needed in "real" programs let translatef = translate :: Vector3 GLfloat -> IO () rotatef = rotate :: GLfloat -> Vector3 GLfloat -> IO () color3f = color :: Color3 GLfloat -> IO () lighting $= Enabled shadeModel $= Smooth translatef (Vector3 (-1) (-1) 0) callList dl1 shadeModel $= Flat translatef (Vector3 0 2 0) preservingMatrix $ do rotatef 300 (Vector3 1 0 0) callList dl2 lighting $= Disabled color3f (Color3 0 1 1) translatef (Vector3 2 (-2) 0) callList dl3 color3f (Color3 1 1 0) translatef (Vector3 0 2 0) callList dl4 flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho (-2.5) 2.5 (-2.5*hf/wf) (2.5*hf/wf) (-10) 10 else ortho (-2.5*wf/hf) (2.5*wf/hf) (-2.5) 2.5 (-10) 10 matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName displayLists <- myInit displayCallback $= display displayLists reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/Polys.hs0000644000000000000000000000560513255126367015617 0ustar0000000000000000{- Polys.hs (adapted from polys.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates polygon stippling. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT fly :: IO GLpolygonstipple fly = newPolygonStipple [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x06, 0xC0, 0x03, 0x60, 0x04, 0x60, 0x06, 0x20, 0x04, 0x30, 0x0C, 0x20, 0x04, 0x18, 0x18, 0x20, 0x04, 0x0C, 0x30, 0x20, 0x04, 0x06, 0x60, 0x20, 0x44, 0x03, 0xC0, 0x22, 0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22, 0x66, 0x01, 0x80, 0x66, 0x33, 0x01, 0x80, 0xCC, 0x19, 0x81, 0x81, 0x98, 0x0C, 0xC1, 0x83, 0x30, 0x07, 0xe1, 0x87, 0xe0, 0x03, 0x3f, 0xfc, 0xc0, 0x03, 0x31, 0x8c, 0xc0, 0x03, 0x33, 0xcc, 0xc0, 0x06, 0x64, 0x26, 0x60, 0x0c, 0xcc, 0x33, 0x30, 0x18, 0xcc, 0x33, 0x18, 0x10, 0xc4, 0x23, 0x08, 0x10, 0x63, 0xC6, 0x08, 0x10, 0x30, 0x0c, 0x08, 0x10, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, 0x08] halftone :: IO GLpolygonstipple halftone = newPolygonStipple . take 128 . cycle $ [ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55] display :: (GLpolygonstipple, GLpolygonstipple) -> DisplayCallback display (flyStipple, halftoneStipple) = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () rectf = rect :: Vertex2 GLfloat -> Vertex2 GLfloat -> IO () color3f (Color3 1 1 1) -- draw one solid, unstippled rectangle, -- then two stippled rectangles rectf (Vertex2 25 25) (Vertex2 125 125) polygonStipple $= Just flyStipple rectf (Vertex2 125 25) (Vertex2 225 125) polygonStipple $= Just halftoneStipple rectf (Vertex2 225 25) (Vertex2 325 125) polygonStipple $= (Nothing :: Maybe GLpolygonstipple) flush myInit :: IO (GLpolygonstipple, GLpolygonstipple) myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat flyStipple <- fly halftoneStipple <- halftone return (flyStipple, halftoneStipple) reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho2D 0.0 (fromIntegral w) 0.0 (fromIntegral h) keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 350 150 _ <- createWindow progName stipples <- myInit displayCallback $= display stipples reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/PolyOff.hs0000644000000000000000000001163413255126367016066 0ustar0000000000000000{- PolyOff.hs (adapted from polyoff.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates polygon offset to draw a shaded polygon and its wireframe counterpart without ugly visual artifacts ("stitching"). -} import Control.Monad ( when ) import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess), exitFailure ) import Graphics.UI.GLUT data State = State { spinX, spinY :: IORef GLfloat, tDist :: IORef GLfloat, polyFactor :: IORef GLfloat, polyUnits :: IORef GLfloat } makeState :: IO State makeState = do x <- newIORef 0 y <- newIORef 0 t <- newIORef 0 f <- newIORef 1 u <- newIORef 1 return $ State { spinX = x, spinY = y, tDist = t, polyFactor = f, polyUnits = u } -- display draws two spheres, one with a gray, diffuse material, the other -- sphere with a magenta material with a specular highlight. display :: State -> DisplayList -> DisplayCallback display state sphereList = do clear [ ColorBuffer, DepthBuffer ] preservingMatrix $ do t <- get (tDist state) translate (Vector3 0 0 t) x <- get (spinX state) rotate x (Vector3 1 0 0) y <- get (spinY state) rotate y (Vector3 0 1 0) materialAmbientAndDiffuse Front $= Color4 0.8 0.8 0.8 1 materialSpecular Front $= Color4 0 0 0 1 materialShininess Front $= 0 lighting $= Enabled light (Light 0) $= Enabled polygonOffsetFill $= Enabled f <- get (polyFactor state) u <- get (polyUnits state) polygonOffset $= (f, u) callList sphereList polygonOffsetFill $= Disabled lighting $= Disabled light (Light 0) $= Disabled color (Color3 1 1 (1 :: GLfloat)) polygonMode $= (Line, Line) callList sphereList polygonMode $= (Fill, Fill) flush -- specify initial properties -- create display list with sphere -- initialize lighting and depth buffer gfxinit :: IO DisplayList gfxinit = do clearColor $= Color4 0 0 0 1 sphereList <- defineNewList Compile $ renderObject Solid (Sphere' 1 20 12) depthFunc $= Just Less ambient (Light 0) $= Color4 0 0 0 1 diffuse (Light 0) $= Color4 1 1 1 1 specular (Light 0) $= Color4 1 1 1 1 position (Light 0) $= Vertex4 1 1 1 0 lightModelAmbient $= Color4 0.2 0.2 0.2 1 return sphereList reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 45 (fromIntegral w / fromIntegral h) 1 10 matrixMode $= Modelview 0 loadIdentity lookAt (Vertex3 0 0 5) (Vertex3 0 0 0) (Vector3 0 1 0) incSpin :: IORef GLfloat -> IO () incSpin spinRef = do let wrap n s = if s > n then s - n else s spinRef $~ (wrap 360 . (+ 5)) postRedisplay Nothing incDist :: State -> GLfloat -> IO () incDist state inc = do newDist <- fmap (+ inc) $ get (tDist state) when (-5 <= newDist && newDist <= 4) $ do tDist state $= newDist postRedisplay Nothing incPoly :: String -> IORef GLfloat -> GLfloat -> IO () incPoly name polyRef inc = do polyRef $~ (+ inc) p <- get polyRef putStrLn (name ++ " is " ++ show p) postRedisplay Nothing keyboardMouse :: State -> KeyboardMouseCallback keyboardMouse state k Down _ _ = case k of (MouseButton LeftButton) -> incSpin (spinX state) (MouseButton MiddleButton) -> incSpin (spinY state) (MouseButton RightButton) -> exitWith ExitSuccess (Char 't') -> incDist state 0.5 (Char 'T') -> incDist state (-0.5) (Char 'F') -> incPoly "polyFactor" (polyFactor state) 0.1 (Char 'f') -> incPoly "polyFactor" (polyFactor state) (-0.1) (Char 'U') -> incPoly "polyUnits" (polyUnits state) 1 (Char 'u') -> incPoly "polyUnits" (polyUnits state) (-1) _ -> return () keyboardMouse _ _ _ _ _ = return () -- Main Loop: Open window with initial window size, title bar, RGBA display -- mode, and handle input events. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] _ <- createWindow progName -- we have to do this *after* createWindow, otherwise we have no OpenGL context version <- get (majorMinor glVersion) when (version == (1,0)) $ do putStrLn "This program demonstrates a feature which is not in OpenGL Version 1.0." putStrLn "If your implementation of OpenGL Version 1.0 has the right extensions," putStrLn "you may be able to modify this program to make it run." exitFailure state <- makeState sphereList <- gfxinit reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboardMouse state) displayCallback $= display state sphereList mainLoop GLUT-2.7.0.16/examples/RedBook4/PointP.hs0000644000000000000000000001157113255126367015721 0ustar0000000000000000{- PointP.hs (adapted from pointp.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates point parameters and their effect on point primitives. 250 points are randomly generated within a 10 by 10 by 40 region, centered at the origin. In some modes (including the default), points that are closer to the viewer will appear larger. Pressing the 'c', 'l', and 'q' keys switch the point parameters attenuation mode to constant, linear, or quadratic, respectively. Pressing the 'f' and 'b' keys move the viewer forward and backwards. In either linear or quadratic attenuation mode, the distance from the viewer to the point will change the size of the point primitive. Pressing the '+' and '-' keys will change the current point size. In this program, the point size is bounded, so it will not get less than 2, nor greater than the maximum returned by pointSizeRange. -} import Control.Monad ( when, unless ) import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess), exitFailure ) import System.Random ( randomRIO ) import Graphics.UI.GLUT type Attenuation = (GLfloat,GLfloat,GLfloat) constant, linear, quadratic :: Attenuation constant = (1, 0, 0 ) linear = (0, 0.12, 0 ) quadratic = (0, 0, 0.01) data State = State { distance :: IORef GLfloat } makeState :: IO State makeState = do d <- newIORef (-10) return $ State { distance = d } -- CFloat has no Random instance, so we go via Float randomGLfloat :: (GLfloat, GLfloat) -> IO GLfloat randomGLfloat = fmap floatToGLfloat . randomRIO . fmapPair glFloatToFloat where fmapPair f (x, y) = (f x, f y) floatToGLfloat = realToFrac :: Float -> GLfloat glFloatToFloat = realToFrac :: GLfloat -> Float randomColor :: IO (Color3 GLfloat) randomColor = do g <- randomGLfloat (0.5, 1) b <- randomGLfloat (0, 1) return $ Color3 1 g b randomVertex :: IO (Vertex3 GLfloat) randomVertex = do x <- randomGLfloat (-5, 5) y <- randomGLfloat (-5, 5) z <- randomGLfloat (-5, -45) return $ Vertex3 x y z myInit :: IO DisplayList myInit = do pointList <- defineNewList Compile $ renderPrimitive Points $ sequence_ $ replicate 250 $ do color =<< randomColor vertex =<< randomVertex depthFunc $= Just Less pointSmooth $= Enabled blend $= Enabled blendFunc $= (SrcAlpha, OneMinusSrcAlpha) pointSize $= 7 pointDistanceAttenuation $= linear pointFadeThresholdSize $= 2 return pointList display :: State -> DisplayList -> DisplayCallback display state pointList = do clear [ ColorBuffer, DepthBuffer ] d <- get (distance state) loadIdentity translate (Vector3 0 0 d) callList pointList swapBuffers reshape :: ReshapeCallback reshape size = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 35 1 0.25 200 matrixMode $= Modelview 0 setPointDistanceAttenuation :: Attenuation -> IO () setPointDistanceAttenuation att = do pointDistanceAttenuation $= att postRedisplay Nothing incDistance :: State -> GLfloat -> IO () incDistance state inc = do distance state $~ (+ inc) postRedisplay Nothing incPointSize :: GLfloat -> IO () incPointSize inc = do newPointSize <- fmap (+ inc) $ get pointSize (_,maxPointSize) <- get pointSizeRange when (2 <= newPointSize && newPointSize <= maxPointSize) $ do pointSize $= newPointSize postRedisplay Nothing keyboard :: State -> KeyboardMouseCallback keyboard state (Char c) Down _ _ = case c of 'c' -> setPointDistanceAttenuation constant 'l' -> setPointDistanceAttenuation linear 'q' -> setPointDistanceAttenuation quadratic 'b' -> incDistance state (-0.5) 'f' -> incDistance state 0.5 '+' -> incPointSize 1 '-' -> incPointSize (-1) '\27' -> exitWith ExitSuccess _ -> return () keyboard _ _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ RGBMode, DoubleBuffered, WithDepthBuffer, Multisampling ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName -- We have to do this *after* createWindow, otherwise we have no OpenGL -- context. Note that the original C example simply tests for OpenGL 1.4 at -- compile time, we do a runtime check for the needed extension. extensions <- get glExtensions unless ("GL_ARB_point_parameters" `elem` extensions) $ do putStrLn "Sorry, this demo requires the GL_ARB_point_parameters extension." exitFailure state <- makeState pointList <- myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard state) displayCallback $= display state pointList mainLoop GLUT-2.7.0.16/examples/RedBook4/Planet.hs0000644000000000000000000000503313255126367015727 0ustar0000000000000000{- Planet.hs (adapted from planet.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program shows how to composite modeling transformations to draw translated and rotated models. Interaction: pressing the d and y keys (day and year) alters the rotation of the planet around the sun. -} import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { year, day :: IORef GLint } makeState :: IO State makeState = do y <- newIORef 0 d <- newIORef 0 return $ State { year = y, day = d } myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat display :: State -> DisplayCallback display state = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () translatef = translate :: Vector3 GLfloat -> IO () color3f (Color3 1 1 1) preservingMatrix $ do renderObject Wireframe (Sphere' 1 20 16) -- draw sun y <- get (year state) rotate (fromIntegral y :: GLfloat) (Vector3 0 1 0) translatef (Vector3 2 0 0) d <- get (day state) rotate (fromIntegral d :: GLfloat) (Vector3 0 1 0) renderObject Wireframe (Sphere' 0.2 10 8) -- draw smaller planet swapBuffers reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 60 (fromIntegral w / fromIntegral h) 1 20 matrixMode $= Modelview 0 loadIdentity lookAt (Vertex3 0 0 5) (Vertex3 0 0 0) (Vector3 0 1 0) keyboard :: State -> KeyboardMouseCallback keyboard state (Char c) Down _ _ = case c of 'd' -> update day 10 'D' -> update day (-10) 'y' -> update year 10 'Y' -> update year (-10) '\27' -> exitWith ExitSuccess _ -> return () where update angle inc = do angle state $~ ((`mod` 360) . (+ inc)) postRedisplay Nothing keyboard _ _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ DoubleBuffered, RGBMode ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName state <- makeState myInit displayCallback $= display state reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard state) mainLoop GLUT-2.7.0.16/examples/RedBook4/PickSquare.hs0000644000000000000000000001046613255126367016561 0ustar0000000000000000{- PickSquare.hs (adapted from picksquare.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE Use of multiple names and picking are demonstrated. A 3x3 grid of squares is drawn. When the left mouse button is pressed, all squares under the cursor position have their color changed. -} import Data.Array ( Array, listArray, (!) ) import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT type Board = Array (Int,Int) (IORef Int) data State = State { board :: Board } makeState :: IO State makeState = do refs <- sequence . replicate 9 . newIORef $ 0 return $ State { board = listArray ((0,0),(2,2)) refs } -- Clear color value for every square on the board myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 -- The nine squares are drawn. Each square is given two names: one for the row -- and the other for the column on the grid. The color of each square is -- determined by its position on the grid, and the value in the board array. -- Note: In contrast to the the original example, we always give names to -- squares, regardless of the render mode. This simplifies the code a bit and -- is even suggested by the Red Book. drawSquares :: State -> IO () drawSquares state = flip mapM_ [ 0 .. 2 ] $ \i -> do loadName (Name (fromIntegral i)) flip mapM_ [ 0 .. 2 ] $ \j -> withName (Name (fromIntegral j)) $ do val <- get (board state ! (i,j)) -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () color3f (Color3 (fromIntegral i / 3.0) (fromIntegral j / 3.0) (fromIntegral val / 3.0)) let vertex2i :: Int -> Int -> Vertex2 GLint vertex2i x y = Vertex2 (fromIntegral x) (fromIntegral y) rect (vertex2i i j) (vertex2i (i + 1) (j + 1)) -- processHits prints the hit records and updates the board array. processHits :: Maybe[HitRecord] -> State -> IO () processHits Nothing _ = putStrLn "selection buffer overflow" processHits (Just hitRecords) state = do putStrLn ("hits = " ++ show (length hitRecords)) mapM_ (\(HitRecord z1 z2 names) -> do putStrLn (" number of names for this hit = " ++ show (length names)) putStr (" z1 is " ++ show z1) putStrLn ("; z2 is " ++ show z2) putStr " names are" sequence_ [ putStr (" " ++ show n) | Name n <- names ] putChar '\n' let [i, j] = [ fromIntegral n | Name n <- names ] (board state ! (i,j)) $~ (\x -> (x + 1) `mod` 3)) hitRecords -- pickSquares sets up selection mode, name stack, and projection matrix for -- picking. Then the objects are drawn. bufSize :: GLsizei bufSize = 512 pickSquares :: State -> KeyboardMouseCallback pickSquares state (MouseButton LeftButton) Down _ (Position x y) = do vp@(_, (Size _ height)) <- get viewport (_, maybeHitRecords) <- getHitRecords bufSize $ withName (Name 0) $ do matrixMode $= Projection preservingMatrix $ do loadIdentity -- create 5x5 pixel picking region near cursor location pickMatrix (fromIntegral x, fromIntegral height - fromIntegral y) (5, 5) vp ortho2D 0 3 0 3 drawSquares state flush processHits maybeHitRecords state postRedisplay Nothing pickSquares _ (Char '\27') Down _ _ = exitWith ExitSuccess pickSquares _ _ _ _ _ = return () display :: State -> DisplayCallback display state = do clear [ ColorBuffer ] drawSquares state flush reshape :: ReshapeCallback reshape size = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho2D 0 3 0 3 matrixMode $= Modelview 0 loadIdentity -- Main Loop main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 100 100 initialWindowPosition $= Position 100 100 _ <- createWindow progName state <- makeState myInit reshapeCallback $= Just reshape displayCallback $= display state keyboardMouseCallback $= Just (pickSquares state) mainLoop GLUT-2.7.0.16/examples/RedBook4/PickDepth.hs0000644000000000000000000001061213255126367016356 0ustar0000000000000000{- PickDepth.hs (adapted from pickdepth.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE Picking is demonstrated in this program. In rendering mode, three overlapping rectangles are drawn. When the left mouse button is pressed, selection mode is entered with the picking matrix. Rectangles which are drawn under the cursor position are "picked." Pay special attention to the depth value range, which is returned. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 depthFunc $= Just Less shadeModel $= Flat depthRange $= (0, 1) -- The default z mapping -- The nine squares are drawn. Each square is given two names: one for the row -- and the other for the column on the grid. The color of each square is -- determined by its position on the grid, and the value in the board array. -- Note: In contrast to the the original example, we always give names to -- squares, regardless of the render mode. This simplifies the code a bit and -- is even suggested by the Red Book. -- The three rectangles are drawn, each with a different name. Note that each -- rectangle is drawn with a different z value. Note: In contrast to the the -- original example, we always give names to squares, regardless of the render -- mode. This simplifies the code a bit and is even suggested by the Red Book. drawRects :: IO () drawRects = do -- resolve overloading, not needed in "real" programs let color3 = color :: Color3 GLfloat -> IO () vertex3 = vertex :: Vertex3 GLint -> IO () loadName (Name 1) renderPrimitive Quads $ do color3 (Color3 1.0 1.0 0.0) vertex3 (Vertex3 2 0 0) vertex3 (Vertex3 2 6 0) vertex3 (Vertex3 6 6 0) vertex3 (Vertex3 6 0 0) loadName (Name 2) renderPrimitive Quads $ do color3 (Color3 0.0 1.0 1.0) vertex3 (Vertex3 3 2 (-1)) vertex3 (Vertex3 3 8 (-1)) vertex3 (Vertex3 8 8 (-1)) vertex3 (Vertex3 8 2 (-1)) loadName (Name 3) renderPrimitive Quads $ do color3 (Color3 1.0 0.0 1.0) vertex3 (Vertex3 0 2 (-2)) vertex3 (Vertex3 0 7 (-2)) vertex3 (Vertex3 5 7 (-2)) vertex3 (Vertex3 5 2 (-2)) -- processHits prints the hit records. processHits :: Maybe[HitRecord] -> IO () processHits Nothing = putStrLn "selection buffer overflow" processHits (Just hitRecords) = do putStrLn ("hits = " ++ show (length hitRecords)) flip mapM_ hitRecords $ \(HitRecord z1 z2 names) -> do putStrLn (" number of names for hit = " ++ show (length names)) putStr (" z1 is " ++ show z1) putStrLn ("; z2 is " ++ show z2) putStr " the name is" sequence_ [ putStr (" " ++ show n) | Name n <- names ] putChar '\n' -- pickRects() sets up selection mode, name stack, and projection matrix for -- picking. Then the objects are drawn. bufSize :: GLsizei bufSize = 512 pickRects :: KeyboardMouseCallback pickRects (MouseButton LeftButton) Down _ (Position x y) = do vp@(_, (Size _ height)) <- get viewport (_, maybeHitRecords) <- getHitRecords bufSize $ withName (Name 0) $ do matrixMode $= Projection preservingMatrix $ do loadIdentity -- create 5x5 pixel picking region near cursor location pickMatrix (fromIntegral x, fromIntegral height - fromIntegral y) (5, 5) vp ortho 0 8 0 8 (-0.5) 2.5 drawRects flush processHits maybeHitRecords postRedisplay Nothing pickRects (Char '\27') Down _ _ = exitWith ExitSuccess pickRects _ _ _ _ = return () display :: DisplayCallback display = do clear [ ColorBuffer, DepthBuffer ] drawRects flush reshape :: ReshapeCallback reshape size = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho 0 8 0 8 (-0.5) 2.5 matrixMode $= Modelview 0 loadIdentity -- Main Loop main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 200 200 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit reshapeCallback $= Just reshape displayCallback $= display keyboardMouseCallback $= Just pickRects mainLoop GLUT-2.7.0.16/examples/RedBook4/Multisamp.hs0000644000000000000000000001130713255126367016460 0ustar0000000000000000{- Multisamp.hs (adapted from multisamp.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program draws shows how to use multisampling to draw anti-aliased geometric primitives. The same display list, a pinwheel of triangles and lines of varying widths, is rendered twice. Multisampling is enabled when the left side is drawn. Multisampling is disabled when the right side is drawn. Pressing the 'b' key toggles drawing of the checkerboard background. Antialiasing is sometimes easier to see when objects are rendered over a contrasting background. -} import Control.Monad ( when ) import Data.Char ( toLower ) import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { bgToggle :: IORef Bool } makeState :: IO State makeState = do b <- newIORef True return $ State { bgToggle = b } data DisplayLists = DisplayLists { pinwheelList, backgroundList :: DisplayList } -- Print out state values related to multisampling. Create display list with -- "pinwheel" of lines and triangles. myInit :: IO DisplayLists myInit = do clearColor $= Color4 0 0 0 0 sb <- get sampleBuffers putStrLn ("number of sample buffers is " ++ show sb) s <- get samples putStrLn ("number of samples is " ++ show s) -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () vertex2f = vertex :: Vertex2 GLfloat -> IO () p <- defineNewList Compile $ do flip mapM_ [ 0 .. 18 ] $ \i -> preservingMatrix $ do rotate (360 * fromIntegral i / 19 :: GLfloat) (Vector3 0 0 1) color3f (Color3 1 1 1) lineWidth $= fromIntegral ((i `mod` 3 :: Int) + 1) renderPrimitive Lines $ do vertex2f (Vertex2 0.25 0.05) vertex2f (Vertex2 0.9 0.2) color3f (Color3 0 1 1) renderPrimitive Triangles $ do vertex2f (Vertex2 0.25 0) vertex2f (Vertex2 0.9 0) vertex2f (Vertex2 0.875 0.1) b <- defineNewList Compile $ do color3f (Color3 1 0.5 0) renderPrimitive Quads $ flip mapM_ [ 0 .. 15 ] $ \i -> flip mapM_ [ 0 .. 15 ] $ \j -> when (((i + j) `mod` 2 :: Int) == 0) $ do let ii = fromIntegral i * 0.25 jj = fromIntegral j * 0.25 vertex2f (Vertex2 (-2.0 + ii) (-2.0 + jj)) vertex2f (Vertex2 (-2.0 + ii) (-1.75 + jj)) vertex2f (Vertex2 (-1.75 + ii) (-1.75 + jj)) vertex2f (Vertex2 (-1.75 + ii) (-2.0 + jj)) return $ DisplayLists { pinwheelList = p, backgroundList = b } -- Draw two sets of primitives, so that you can compare the user of -- multisampling against its absence. -- -- This code enables antialiasing and draws one display list and disables and -- draws the other display list display :: State -> DisplayLists -> DisplayCallback display state displayLists = do clear [ ColorBuffer ] t <- get (bgToggle state) when t $ callList (backgroundList displayLists) -- resolve overloading, not needed in "real" programs let translatef = translate :: Vector3 GLfloat -> IO () multisample $= Enabled preservingMatrix $ do translatef (Vector3 (-1) 0 0) callList (pinwheelList displayLists) multisample $= Disabled preservingMatrix $ do translatef (Vector3 1 0 0) callList (pinwheelList displayLists) swapBuffers reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= 2 * h then ortho2D (-2) 2 (-2*hf/wf) (2*hf/wf) else ortho2D (-2*wf/hf) (2*wf/hf) (-2) 2 matrixMode $= Modelview 0 loadIdentity keyboard :: State -> KeyboardMouseCallback keyboard state (Char c) Down _ _ = case toLower c of 'b' -> do bgToggle state $~ not; postRedisplay Nothing '\27' -> exitWith ExitSuccess _ -> return () keyboard _ _ _ _ _ = return () -- Main Loop: Open window with initial window size, title bar, RGBA display -- mode, and handle input events. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ DoubleBuffered, RGBMode, Multisampling ] initialWindowSize $= Size 600 300 _ <- createWindow progName state <- makeState displayLists <- myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard state) displayCallback $= display state displayLists mainLoop GLUT-2.7.0.16/examples/RedBook4/MultiTex.hs0000644000000000000000000001025613255126367016262 0ustar0000000000000000{- MultiTex.hs (adapted from multitex.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE -} import Control.Monad ( unless ) import Foreign ( withArray ) import System.Exit ( exitFailure, exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT specifyTexture :: TextureSize2D -> (GLubyte -> GLubyte -> Color4 GLubyte) -> IO () specifyTexture size@(TextureSize2D w h) f = withArray [ f i j | i <- [ 0 .. fromIntegral w - 1 ], j <- [ 0 .. fromIntegral h - 1] ] $ texImage2D Texture2D NoProxy 0 RGBA' size 0 . PixelData RGBA UnsignedByte myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat depthFunc $= Just Less rowAlignment Unpack $= 1 [texName0, texName1] <- genObjectNames 2 textureBinding Texture2D $= Just texName0 -- Note: We use much brighter colors than in the original example where -- everything was almost black. specifyTexture (TextureSize2D 32 32) (\i j -> Color4 (i*8) (j*8) ((i*j) `div` 4) 255) textureFilter Texture2D $= ((Nearest, Nothing), Nearest) textureWrapMode Texture2D S $= (Repeated, Repeat) textureWrapMode Texture2D T $= (Repeated, Repeat) textureBinding Texture2D $= Just texName1 specifyTexture (TextureSize2D 16 16) (\i j -> Color4 255 (i*16) (j*16) 255) textureFilter Texture2D $= ((Linear', Nothing), Linear') textureWrapMode Texture2D S $= (Repeated, ClampToEdge) textureWrapMode Texture2D T $= (Repeated, ClampToEdge) -- Use the two texture objects to define two texture units -- for use in multitexturing activeTexture $= TextureUnit 0 texture Texture2D $= Enabled textureBinding Texture2D $= Just texName0 textureFunction $= Replace matrixMode $= Texture loadIdentity translate (Vector3 0.5 0.5 (0 :: GLfloat)) rotate (45 :: GLfloat) (Vector3 0 0 1) translate (Vector3 (-0.5) (-0.5) (0 :: GLfloat)) matrixMode $= Modelview 0 activeTexture $= TextureUnit 1 texture Texture2D $= Enabled textureBinding Texture2D $= Just texName1 textureFunction $= Modulate display :: DisplayCallback display = do clear [ ColorBuffer, DepthBuffer ] -- resolve overloading, not needed in "real" programs let multiTexCoord2f = multiTexCoord :: TextureUnit -> TexCoord2 GLfloat -> IO () vertex2f = vertex :: Vertex2 GLfloat -> IO () renderPrimitive Triangles $ do multiTexCoord2f (TextureUnit 0) (TexCoord2 0 0) multiTexCoord2f (TextureUnit 1) (TexCoord2 1 0) vertex2f (Vertex2 0 0) multiTexCoord2f (TextureUnit 0) (TexCoord2 0.5 1) multiTexCoord2f (TextureUnit 1) (TexCoord2 0.5 0) vertex2f (Vertex2 50 100) multiTexCoord2f (TextureUnit 0) (TexCoord2 1 0) multiTexCoord2f (TextureUnit 1) (TexCoord2 1 1) vertex2f (Vertex2 100 0) flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho2D 0 100 0 (100*hf/wf) else ortho2D 0 (100*wf/hf) 0 100 matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 250 250 initialWindowPosition $= Position 100 100 _ <- createWindow progName -- we have to do this *after* createWindow, otherwise we have no OpenGL context version <- get (majorMinor glVersion) unless (version >= (1, 3)) $ do exts <- get glExtensions unless ("GL_ARB_multitexture" `elem` exts && -- part of 1.3 core "GL_EXT_texture_object" `elem` exts) $ do -- part of 1.1 core putStrLn "Sorry, this demo requires the GL_ARB_multitexture and GL_EXT_texture_object extensions." exitFailure myInit reshapeCallback $= Just reshape displayCallback $= display keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/MoveLight.hs0000644000000000000000000000537513255126367016413 0ustar0000000000000000{- MoveLight.hs (adapted from movelight.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates when to issue lighting and transformation commands to render a model with a light which is moved by a modeling transformation (rotate or translate). The light position is reset after the modeling transformation is called. The eye position does not change. A sphere is drawn using a grey material characteristic. A single light source illuminates the object. Interaction: pressing the left mouse button alters the modeling transformation (x rotation) by 30 degrees. The scene is then redrawn with the light in a new position. -} import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { spin :: IORef Int } makeState :: IO State makeState = do s <- newIORef 0 return $ State { spin = s } myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Smooth lighting $= Enabled light (Light 0) $= Enabled depthFunc $= Just Less display :: State -> DisplayCallback display state = do clear [ ColorBuffer, DepthBuffer ] preservingMatrix $ do lookAt (Vertex3 0 0 5) (Vertex3 0 0 0) (Vector3 0 1 0) preservingMatrix $ do s <- get (spin state) rotate (fromIntegral s :: GLdouble) (Vector3 1 0 0) position (Light 0) $= Vertex4 0 0 1.5 1 translate (Vector3 0 0 1.5 :: Vector3 GLdouble) lighting $= Disabled color (Color3 0 1 1 :: Color3 GLfloat) renderObject Wireframe (Cube 0.1) lighting $= Enabled renderObject Solid (Torus 0.275 0.85 8 15) flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 40 (fromIntegral w / fromIntegral h) 1 20 matrixMode $= Modelview 0 loadIdentity keyboardMouse :: State -> KeyboardMouseCallback keyboardMouse state (MouseButton LeftButton) Down _ _ = do spin state $~ ((`mod` 360) . (+ 30)) postRedisplay Nothing keyboardMouse _ (Char '\27') Down _ _ = exitWith ExitSuccess keyboardMouse _ _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName state <- makeState myInit displayCallback $= display state reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboardMouse state) mainLoop GLUT-2.7.0.16/examples/RedBook4/Model.hs0000644000000000000000000000451613255126367015551 0ustar0000000000000000{- Model.hs (adapted from model.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates modeling transformations. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat drawTriangle :: IO () drawTriangle = do -- resolve overloading, not needed in "real" programs let vertex2f = vertex :: Vertex2 GLfloat -> IO () renderPrimitive LineLoop $ do vertex2f (Vertex2 0 25 ) vertex2f (Vertex2 25 (-25)) vertex2f (Vertex2 (-25) (-25)) display :: DisplayCallback display = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () translatef = translate :: Vector3 GLfloat -> IO () scalef = scale :: GLfloat -> GLfloat -> GLfloat -> IO () rotatef = rotate :: GLfloat -> Vector3 GLfloat -> IO () color3f (Color3 1 1 1) loadIdentity color3f (Color3 1 1 1) drawTriangle lineStipple $= Just (1, 0xF0F0) loadIdentity translatef (Vector3 (-20) 0 0) drawTriangle lineStipple $= Just (1, 0xF00F) loadIdentity scalef 1.5 0.5 1.0 drawTriangle lineStipple $= Just (1, 0x8888) loadIdentity rotatef 90 (Vector3 0 0 1) drawTriangle lineStipple $= Nothing flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho (-50) 50 (-50 * hf/wf) (50 * hf/wf) (-1) 1 else ortho (-50 * wf/hf) (50 * wf/hf) (-50) 50 (-1) 1 matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit displayCallback $= display reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/Mipmap.hs0000644000000000000000000000677213255126367015742 0ustar0000000000000000{- Mipmap.hs (adapted from mipmap.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates using mipmaps for texture maps. To overtly show the effect of mipmaps, each mipmap reduction level has a solidly colored, contrasting texture image. Thus, the quadrilateral which is drawn is drawn with several different colors. -} import Control.Monad ( when ) import Data.Maybe ( isJust ) import Foreign ( withArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT makeImage :: Level -> TextureSize2D -> Color4 GLubyte -> IO () makeImage level size@(TextureSize2D w h) col = withArray (replicate (fromIntegral (w * h)) col) $ texImage2D Texture2D NoProxy level RGBA' size 0 . PixelData RGBA UnsignedByte makeImages :: [Color4 GLubyte] -> IO () makeImages colors = sequence_ $ zipWith3 makeImage levels sizes colors where numLevels = length colors levels = [ 0 .. fromIntegral numLevels - 1 ] sizes = reverse (take numLevels [ TextureSize2D s s | s <- iterate (* 2) 1 ]) myInit :: IO (Maybe TextureObject) myInit = do depthFunc $= Just Less shadeModel $= Flat translate (Vector3 0 0 (-3.6 :: GLfloat)) rowAlignment Unpack $= 1 exts <- get glExtensions mbTexName <- if "GL_EXT_texture_object" `elem` exts then fmap Just genObjectName else return Nothing when (isJust mbTexName) $ textureBinding Texture2D $= mbTexName textureWrapMode Texture2D S $= (Repeated, Repeat) textureWrapMode Texture2D T $= (Repeated, Repeat) textureFilter Texture2D $= ((Nearest, Just Nearest), Nearest) makeImages [ Color4 255 255 0 255, Color4 255 0 255 255, Color4 255 0 0 255, Color4 0 255 0 255, Color4 0 0 255 255, Color4 255 255 255 255 ] textureFunction $= Decal texture Texture2D $= Enabled return mbTexName display :: Maybe TextureObject -> DisplayCallback display mbTexName = do clear [ ColorBuffer, DepthBuffer ] when (isJust mbTexName) $ textureBinding Texture2D $= mbTexName -- resolve overloading, not needed in "real" programs let texCoord2f = texCoord :: TexCoord2 GLfloat -> IO () vertex3f = vertex :: Vertex3 GLfloat -> IO () renderPrimitive Quads $ do texCoord2f (TexCoord2 0 0); vertex3f (Vertex3 ( -2) (-1) 0 ) texCoord2f (TexCoord2 0 8); vertex3f (Vertex3 ( -2) 1 0 ) texCoord2f (TexCoord2 8 8); vertex3f (Vertex3 2000 1 (-6000)) texCoord2f (TexCoord2 8 0); vertex3f (Vertex3 2000 (-1) (-6000)) flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 60 (fromIntegral w / fromIntegral h) 1 30000 matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 50 50 _ <- createWindow progName texName <- myInit displayCallback $= display texName reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/Minmax.hs0000644000000000000000000000426113255126367015737 0ustar0000000000000000{- Minmax.hs (adapted from minmax.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE Determine the minimum and maximum values of a group of pixels. This demonstrates use of the minmax function. -} import Foreign ( allocaArray, peekArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT import ReadImage myInit :: IO () myInit = do rowAlignment Unpack $= 1 clearColor $= Color4 0 0 0 0 minmax $= Just (RGB', PassThrough) display :: Size -> PixelData a -> DisplayCallback display size pixels = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let rasterPos2i = rasterPos :: Vertex2 GLint -> IO () rasterPos2i (Vertex2 1 1) drawPixels size pixels flush [Color3 minR minG minB, Color3 maxR maxG maxB] <- allocaArray 2 $ \buf -> do getMinmax Reset (PixelData RGB UnsignedByte buf) peekArray 2 buf :: IO [Color3 GLubyte] putStrLn (" Red : min = " ++ show minR ++ " max = " ++ show maxR) putStrLn (" Green : min = " ++ show minG ++ " max = " ++ show maxG) putStrLn (" Blue : min = " ++ show minB ++ " max = " ++ show maxB) reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho 0 (fromIntegral w) 0 (fromIntegral h) (-1) 1 matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () -- Main Loop: Open window with initial window size, title bar, RGBA display -- mode, and handle input events. main :: IO () main = do (progName, args) <- getArgsAndInitialize (size, pixels) <- readImage (if null args then "Data/leeds.bin" else head args) initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= size initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard displayCallback $= display size pixels mainLoop GLUT-2.7.0.16/examples/RedBook4/ReadImage.hs0000644000000000000000000000472113255126367016325 0ustar0000000000000000{- ReadImage.hs (adapted from readImage.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE Support for reading a file of raw RGB data: 4 bytes big-endian width 4 bytes big-endian height width * height RGB byte triples -} module ReadImage ( readImage ) where import Data.Word ( Word8, Word32 ) import Control.Exception ( bracket ) import Control.Monad ( when ) import System.IO ( Handle, IOMode(ReadMode), openBinaryFile, hGetBuf, hClose ) import System.IO.Error ( mkIOError, eofErrorType ) import Foreign ( Ptr, alloca, mallocBytes, Storable(..) ) import Graphics.UI.GLUT -- This is probably overkill, but anyway... newtype Word32BigEndian = Word32BigEndian Word32 word32BigEndianToGLsizei :: Word32BigEndian -> GLsizei word32BigEndianToGLsizei (Word32BigEndian x) = fromIntegral x instance Storable Word32BigEndian where sizeOf ~(Word32BigEndian x) = sizeOf x alignment ~(Word32BigEndian x) = alignment x peek ptr = do let numBytes = sizeOf (undefined :: Word32BigEndian) bytes <- mapM (peekByteOff ptr) [ 0 .. numBytes - 1 ] :: IO [Word8] let value = foldl (\val byte -> val * 256 + fromIntegral byte) 0 bytes return $ Word32BigEndian value poke = error "" -- This is the reason for all this stuff above... readGLsizei :: Handle -> IO GLsizei readGLsizei handle = alloca $ \buf -> do hGetBufFully handle buf (sizeOf (undefined :: Word32BigEndian)) fmap word32BigEndianToGLsizei $ peek buf -- A handy variant of hGetBuf with additional error checking hGetBufFully :: Handle -> Ptr a -> Int -> IO () hGetBufFully handle ptr numBytes = do bytesRead <- hGetBuf handle ptr numBytes when (bytesRead /= numBytes) $ ioError $ mkIOError eofErrorType "hGetBufFully" (Just handle) Nothing -- Closing a file is nice, even when an error occurs during reading. withBinaryFile :: FilePath -> (Handle -> IO a) -> IO a withBinaryFile filePath = bracket (openBinaryFile filePath ReadMode) hClose readImage :: FilePath -> IO (Size, PixelData a) readImage filePath = withBinaryFile filePath $ \handle -> do width <- readGLsizei handle height <- readGLsizei handle let numBytes = fromIntegral (3 * width * height) buf <- mallocBytes numBytes hGetBufFully handle buf numBytes return (Size width height, PixelData RGB UnsignedByte buf) GLUT-2.7.0.16/examples/RedBook4/Material.hs0000644000000000000000000001307013255126367016242 0ustar0000000000000000{- Material.hs (adapted from material.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates the use of the GL lighting model. Several objects are drawn using different material characteristics. A single light source illuminates the objects. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT -- Initialize z-buffer, projection matrix, light source, and lighting model. -- Do not specify a material property here. myInit :: IO () myInit = do clearColor $= Color4 0 0.1 0.1 0 depthFunc $= Just Less shadeModel $= Smooth ambient (Light 0) $= Color4 0 0 0 1 diffuse (Light 0) $= Color4 1 1 1 1 position (Light 0) $= Vertex4 0 3 2 0 lightModelAmbient $= Color4 0.4 0.4 0.4 1 lightModelLocalViewer $= Disabled lighting $= Enabled light (Light 0) $= Enabled -- Draw twelve spheres in 3 rows with 4 columns. -- The spheres in the first row have materials with no ambient reflection. -- The second row has materials with significant ambient reflection. -- The third row has materials with colored ambient reflection. -- -- The first column has materials with blue, diffuse reflection only. -- The second column has blue diffuse reflection, as well as specular -- reflection with a low shininess exponent. -- The third column has blue diffuse reflection, as well as specular -- reflection with a high shininess exponent (a more concentrated highlight). -- The fourth column has materials which also include an emissive component. -- -- translate is used to move spheres to their appropriate locations. display :: DisplayCallback display = do clear [ ColorBuffer, DepthBuffer ] let draw :: GLfloat -> GLfloat -> Color4 GLfloat -> Color4 GLfloat -> Color4 GLfloat -> GLfloat -> Color4 GLfloat -> IO () draw row column amb dif spc shi emi = preservingMatrix $ do translate (Vector3 (2.5 * (column - 2.5)) (3 * (2 - row)) 0) materialAmbient Front $= amb materialDiffuse Front $= dif materialSpecular Front $= spc materialShininess Front $= shi materialEmission Front $= emi renderObject Solid (Sphere' 1 16 16) noMat = Color4 0 0 0 1 matAmbient = Color4 0.7 0.7 0.7 1 matAmbientColor = Color4 0.8 0.8 0.2 1 matDiffuse = Color4 0.1 0.5 0.8 1 matSpecular = Color4 1 1 1 1 noShininess = 0 lowShininess = 5 highShininess = 100 matEmission = Color4 0.3 0.2 0.2 0 -- draw sphere in first row, first column -- diffuse reflection only; no ambient or specular draw 1 1 noMat matDiffuse noMat noShininess noMat -- draw sphere in first row, second column -- diffuse and specular reflection; low shininess; no ambient draw 1 2 noMat matDiffuse matSpecular lowShininess noMat -- draw sphere in first row, third column -- diffuse and specular reflection; high shininess; no ambient draw 1 3 noMat matDiffuse matSpecular highShininess noMat -- draw sphere in first row, fourth column -- diffuse reflection; emission; no ambient or specular reflection draw 1 4 noMat matDiffuse noMat noShininess matEmission -- draw sphere in second row, first column -- ambient and diffuse reflection; no specular draw 2 1 matAmbient matDiffuse noMat noShininess noMat -- draw sphere in second row, second column -- ambient, diffuse and specular reflection; low shininess draw 2 2 matAmbient matDiffuse matSpecular lowShininess noMat -- draw sphere in second row, third column -- ambient, diffuse and specular reflection; high shininess draw 2 3 matAmbient matDiffuse matSpecular highShininess noMat -- draw sphere in second row, fourth column -- ambient and diffuse reflection; emission; no specular draw 2 4 matAmbient matDiffuse noMat noShininess matEmission -- draw sphere in third row, first column -- colored ambient and diffuse reflection; no specular draw 3 1 matAmbientColor matDiffuse noMat noShininess noMat -- draw sphere in third row, second column -- colored ambient, diffuse and specular reflection; low shininess draw 3 2 matAmbientColor matDiffuse matSpecular lowShininess noMat -- draw sphere in third row, third column -- colored ambient, diffuse and specular reflection; high shininess draw 3 3 matAmbientColor matDiffuse matSpecular highShininess noMat -- draw sphere in third row, fourth column -- colored ambient and diffuse reflection; emission; no specular draw 3 4 matAmbientColor matDiffuse noMat noShininess matEmission flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h * 2 then ortho (-6) 6 (-3 * (hf * 2) / wf) (3 * (hf * 2) / wf) (-10) 10 else ortho (-6 * wf / (hf * 2)) (6 * wf / (hf * 2)) (-3) 3 (-10) 10 matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 600 450 _ <- createWindow progName myInit reshapeCallback $= Just reshape displayCallback $= display keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/MVArray.hs0000644000000000000000000000555413255126367016035 0ustar0000000000000000{- MVArray.hs (adapted from mvarray.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates multiple vertex arrays, specifically the OpenGL routine multiDrawElements. -} import Control.Monad ( unless ) import Data.List ( genericLength ) import Foreign ( Storable, Ptr, newArray ) import System.Exit ( exitFailure, exitWith, ExitCode(..) ) import Graphics.UI.GLUT data MultiDrawInfo a = MultiDrawInfo (Ptr GLsizei) (Ptr (Ptr a)) GLsizei makeMultiDrawInfo :: Storable a => [[a]] -> IO (MultiDrawInfo a) makeMultiDrawInfo indicesLists = do count <- newArray $ map genericLength indicesLists indices <- newArray =<< mapM newArray indicesLists return $ MultiDrawInfo count indices (genericLength indicesLists) setupPointer :: IO () setupPointer = do clientState VertexArray $= Enabled vertices <- newArray ([ Vertex2 25 25, Vertex2 75 75, Vertex2 100 125, Vertex2 150 75, Vertex2 200 175, Vertex2 250 150, Vertex2 300 125, Vertex2 100 200, Vertex2 150 250, Vertex2 200 225, Vertex2 250 300, Vertex2 300 250 ] :: [Vertex2 GLint]) arrayPointer VertexArray $= VertexArrayDescriptor 2 Int 0 vertices myInit :: IO (MultiDrawInfo GLubyte) myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Smooth setupPointer makeMultiDrawInfo [ [ 0, 1, 2, 3, 4, 5, 6 ], [ 1, 7, 8, 9, 10, 11 ] ] display :: MultiDrawInfo GLubyte -> DisplayCallback display (MultiDrawInfo count indices primCount) = do clear [ ColorBuffer ] color (Color3 1 1 1 :: Color3 GLfloat) multiDrawElements LineStrip count UnsignedByte indices primCount flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho2D 0 (fromIntegral w) 0 (fromIntegral h) -- the following line is not in the original example, but it's good style... matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 350 350 initialWindowPosition $= Position 100 100 _ <- createWindow progName -- we have to do this *after* createWindow, otherwise we have no OpenGL context exts <- get glExtensions unless ("GL_EXT_multi_draw_arrays" `elem` exts) $ do putStrLn "Sorry, this demo requires the GL_EXT_multi_draw_arrays extension." exitFailure multiDrawInfo <- myInit displayCallback $= display multiDrawInfo reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/Lines.hs0000644000000000000000000000575413255126367015570 0ustar0000000000000000{- Lines.hs (adapted from lines.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates geometric primitives and their attributes. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT drawOneLine :: Vertex2 GLfloat -> Vertex2 GLfloat -> IO () drawOneLine p1 p2 = renderPrimitive Lines $ do vertex p1; vertex p2 myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat display :: DisplayCallback display = do clear [ ColorBuffer ] -- select white for all lines color (Color3 1.0 1.0 1.0 :: Color3 GLfloat) -- in 1st row, 3 lines, each with a different stipple lineStipple $= Just (1, 0x0101) -- dotted drawOneLine (Vertex2 50 125) (Vertex2 150 125) lineStipple $= Just (1, 0x00FF) -- dashed drawOneLine (Vertex2 150 125) (Vertex2 250 125) lineStipple $= Just (1, 0x1C47) -- dash/dot/dash drawOneLine (Vertex2 250 125) (Vertex2 350 125) -- in 2nd row, 3 wide lines, each with different stipple lineWidth $= 5.0 lineStipple $= Just (1, 0x0101) -- dotted drawOneLine (Vertex2 50 100) (Vertex2 150 100) lineStipple $= Just (1, 0x00FF) -- dashed drawOneLine (Vertex2 150 100) (Vertex2 250 100) lineStipple $= Just (1, 0x1C47) -- dash/dot/dash drawOneLine (Vertex2 250 100) (Vertex2 350 100) lineWidth $= 1.0 -- in 3rd row, 6 lines, with dash/dot/dash stipple -- as part of a single connected line strip lineStipple $= Just (1, 0x1C47) -- dash/dot/dash renderPrimitive LineStrip $ mapM_ vertex [ Vertex2 (50+(i*50)) (75 :: GLint) | i <- [0..6] ] -- in 4th row, 6 independent lines with same stipple sequence_ [ drawOneLine (Vertex2 (50+( i *50)) 50) (Vertex2 (50+((i+1)*50)) 50) | i <- [0..5] ] -- in 5th row, 1 line, with dash/dot/dash stipple -- and a stipple repeat factor of 5 lineStipple $= Just (5, 0x1C47) -- dash/dot/dash drawOneLine (Vertex2 50 25) (Vertex2 350 25) lineStipple $= Nothing flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho2D 0 (fromIntegral w) 0 (fromIntegral h) -- the following line is not in the original example, but it's good style... matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () -- Request double buffer display mode. -- Register mouse input callback functions main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 400 150 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit displayCallback $= display reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/Light.hs0000644000000000000000000000342413255126367015555 0ustar0000000000000000{- Light.hs (adapted from light.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates the use of the OpenGL lighting model. A sphere is drawn using a grey material characteristic. A single light source illuminates the object. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Smooth materialSpecular Front $= Color4 1 1 1 1 materialShininess Front $= 50 position (Light 0) $= Vertex4 1 1 1 0 lighting $= Enabled light (Light 0) $= Enabled depthFunc $= Just Less display :: DisplayCallback display = do clear [ ColorBuffer, DepthBuffer ] renderObject Solid (Sphere' 1 20 16) flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho (-1.5) 1.5 (-1.5 * hf/wf) (1.5 * hf/wf) (-10) 10 else ortho (-1.5 * wf/hf) (1.5 * wf/hf) (-1.5) 1.5 (-10) 10 matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit displayCallback $= display reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/Image.hs0000644000000000000000000000751613255126367015536 0ustar0000000000000000{- Image.hs (adapted from image.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates drawing pixels and shows the effect of drawPixels, copyPixels, and pixelZoom. Interaction: moving the mouse while pressing the mouse button will copy the image in the lower-left corner of the window to the mouse position, using the current pixel zoom factors. There is no attempt to prevent you from drawing over the original image. If you press the 'r' key, the original image and zoom factors are reset. If you press the 'z' or 'Z' keys, you change the zoom factors. -} import Data.Bits ( (.&.) ) import Data.IORef ( IORef, newIORef ) import Foreign ( newArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { zoomFactor :: IORef GLfloat } makeState :: IO State makeState = do z <- newIORef 1 return $ State { zoomFactor = z } -- Create checkerboard image checkImageSize :: Size checkImageSize = Size 64 64 type Image = PixelData (Color3 GLubyte) makeCheckImage :: Size -> GLsizei -> (GLubyte -> (Color3 GLubyte)) -> IO Image makeCheckImage (Size w h) n f = fmap (PixelData RGB UnsignedByte) $ newArray [ f c | i <- [ 0 .. w - 1 ], j <- [ 0 .. h - 1 ], let c | (i .&. n) == (j .&. n) = 0 | otherwise = 255 ] myInit :: IO Image myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat rowAlignment Unpack $= 1 makeCheckImage checkImageSize 0x8 (\c -> Color3 c c c) display :: Image -> DisplayCallback display pixelData = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let rasterPos2i = rasterPos :: Vertex2 GLint -> IO () rasterPos2i (Vertex2 0 0) drawPixels checkImageSize pixelData flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho2D 0 (fromIntegral w) 0 (fromIntegral h) matrixMode $= Modelview 0 loadIdentity motion :: State -> MotionCallback motion state (Position x y) = do Size _ height <- get windowSize let screenY = fromIntegral height - y -- resolve overloading, not needed in "real" programs let rasterPos2i = rasterPos :: Vertex2 GLint -> IO () rasterPos2i (Vertex2 x screenY) z <- get (zoomFactor state) pixelZoom $= (z, z) copyPixels (Position 0 0) checkImageSize CopyColor pixelZoom $= (1, 1) flush resetZoomFactor :: State -> IO () resetZoomFactor state = do zoomFactor state $= 1.0 postRedisplay Nothing putStrLn "zoomFactor reset to 1.0" incZoomFactor :: State -> GLfloat -> IO () incZoomFactor state inc = do zoomFactor state $~! (max 0.5 . min 3.0 . (+ inc)) get (zoomFactor state) >>= putStrLn . ("zoomFactor is now " ++) . show keyboard :: State -> KeyboardMouseCallback keyboard state (Char 'r') Down _ _ = resetZoomFactor state keyboard state (Char 'R') Down _ _ = resetZoomFactor state keyboard state (Char 'z') Down _ _ = incZoomFactor state 0.5 keyboard state (Char 'Z') Down _ _ = incZoomFactor state (-0.5) keyboard _ (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 250 250 initialWindowPosition $= Position 100 100 _ <- createWindow progName state <- makeState checkImage <- myInit displayCallback $= display checkImage reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard state) motionCallback $= Just (motion state) mainLoop GLUT-2.7.0.16/examples/RedBook4/Histogram.hs0000644000000000000000000000556213255126367016450 0ustar0000000000000000{- Histogram.hs (adapted from histogram.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE Compute the histogram of the image. This program illustrates the use of the histogram function. -} import Control.Monad ( zipWithM_ ) import Foreign ( allocaArray, peekArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT import ReadImage histogramSize :: Int histogramSize = 256 -- Must be a power of 2 myInit :: IO () myInit = do rowAlignment Unpack $= 1 clearColor $= Color4 0 0 0 0 histogram NoProxy $= Just (fromIntegral histogramSize, RGB', PassThrough) display :: Size -> PixelData a -> DisplayCallback display size pixels = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let rasterPos2i = rasterPos :: Vertex2 GLint -> IO () rasterPos2i (Vertex2 1 1) drawPixels size pixels values <- allocaArray histogramSize $ \buf -> do -- Note: The example in the Red Book uses GL_UNSIGNED_SHORT here, -- but we are more honest by using Short... getHistogram Reset (PixelData RGB Short buf) peekArray histogramSize buf -- Plot histogram zipWithM_ (plotHistogram values) [ Color3 1 0 0, Color3 0 1 0, Color3 0 0 1 ] [\(Color3 r _ _) -> r, \(Color3 _ g _) -> g, \(Color3 _ _ b) -> b ] flush plotHistogram :: [Color3 GLshort] -> Color3 GLfloat -> (Color3 GLshort -> GLshort) -> IO () plotHistogram values c selectComponent = renderPrimitive LineStrip $ do color c zipWithM_ (\i h -> vertex (Vertex2 i (selectComponent h))) [ 0 .. ] values reshape :: ReshapeCallback reshape size = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho 0 (fromIntegral histogramSize) 0 10000 (-1) 1 matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char 's') Down _ _ = do Just (width, format, sink) <- get (histogram NoProxy) let newSink = if sink == Sink then PassThrough else Sink histogram NoProxy $= Just (width, format, newSink) postRedisplay Nothing keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () -- Main Loop: Open window with initial window size, title bar, RGBA display -- mode, and handle input events. main :: IO () main = do (progName, args) <- getArgsAndInitialize (size, pixels) <- readImage (if null args then "Data/leeds.bin" else head args) initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= size initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard displayCallback $= display size pixels mainLoop GLUT-2.7.0.16/examples/RedBook4/Hello.hs0000644000000000000000000000312113255126367015543 0ustar0000000000000000{- Hello.hs (adapted from hello.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This is a simple, introductory OpenGL program. -} import Graphics.UI.GLUT display :: DisplayCallback display = do -- clear all pixels clear [ ColorBuffer ] -- draw white polygon (rectangle) with corners at -- (0.25, 0.25, 0.0) and (0.75, 0.75, 0.0) color (Color3 1.0 1.0 (1.0 :: GLfloat)) -- resolve overloading, not needed in "real" programs let vertex3f = vertex :: Vertex3 GLfloat -> IO () renderPrimitive Polygon $ mapM_ vertex3f [ Vertex3 0.25 0.25 0.0, Vertex3 0.75 0.25 0.0, Vertex3 0.75 0.75 0.0, Vertex3 0.25 0.75 0.0] -- don't wait! -- start processing buffered OpenGL routines flush myInit :: IO () myInit = do -- select clearing color clearColor $= Color4 0 0 0 0 -- initialize viewing values matrixMode $= Projection loadIdentity ortho 0 1 0 1 (-1) 1 -- Declare initial window size, position, and display mode (single buffer and -- RGBA). Open window with "hello" in its title bar. Call initialization -- routines. Register callback function to display graphics. Enter main loop and -- process events. main :: IO () main = do _ <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 250 250 initialWindowPosition $= Position 100 100 _ <- createWindow "hello" myInit displayCallback $= display mainLoop GLUT-2.7.0.16/examples/RedBook4/Font.hs0000644000000000000000000001241413255126367015413 0ustar0000000000000000{- Font.hs (adapted from font.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE Draws some text in a bitmapped font. Uses bitmap and other pixel routines. Also demonstrates use of display lists. -} import Control.Monad ( zipWithM_ ) import Data.List ( genericDrop, genericLength ) import Foreign.C.String ( castCharToCChar ) import Foreign.Marshal.Array ( withArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT space :: [GLubyte] space = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] letters :: [[GLubyte]] letters = [ [ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18 ], [ 0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe ], [ 0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e ], [ 0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc ], [ 0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff ], [ 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff ], [ 0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e ], [ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3 ], [ 0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e ], [ 0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 ], [ 0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3 ], [ 0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 ], [ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3 ], [ 0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3 ], [ 0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e ], [ 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe ], [ 0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c ], [ 0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe ], [ 0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e ], [ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff ], [ 0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3 ], [ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3 ], [ 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3 ], [ 0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3 ], [ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3 ], [ 0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff ]] charToGLubyte :: Char -> GLubyte charToGLubyte = fromIntegral . castCharToCChar makeRasterFont :: IO DisplayList makeRasterFont = do rowAlignment Unpack $= 1 fontDisplayLists@(fontOffset:_) <- genObjectNames 128 let listsStartingWith ch = genericDrop (charToGLubyte ch) fontDisplayLists makeLetter dl letter = defineList dl Compile $ withArray letter $ bitmap (Size 8 13) (Vertex2 0 2) (Vector2 10 0) zipWithM_ makeLetter (listsStartingWith 'A') letters makeLetter (head (listsStartingWith ' ')) space return fontOffset myInit :: IO DisplayList myInit = do shadeModel $= Flat makeRasterFont printString :: DisplayList -> String -> IO () printString fontOffset s = preservingAttrib [ ListAttributes ] $ do listBase $= fontOffset withArray (map charToGLubyte s) $ callLists (genericLength s) UnsignedByte -- Everything above this line could be in a library -- that defines a font. To make it work, you've got -- to call makeRasterFont before you start making -- calls to printString. display :: DisplayList -> DisplayCallback display fontOffset = do let white = Color3 1 1 1 clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () rasterPos2i = rasterPos :: Vertex2 GLint -> IO () color3f white rasterPos2i (Vertex2 20 60) printString fontOffset "THE QUICK BROWN FOX JUMPS" rasterPos2i (Vertex2 20 40) printString fontOffset "OVER A LAZY DOG" flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho 0 (fromIntegral w) 0 (fromIntegral h) (-1) 1 matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () -- Main Loop -- Open window with initial window size, title bar, -- RGBA display mode, and handle input events. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 300 100 initialWindowPosition $= Position 100 100 _ <- createWindow progName fontOffset <- myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard displayCallback $= display fontOffset mainLoop GLUT-2.7.0.16/examples/RedBook4/FogIndex.hs0000644000000000000000000000446713255126367016221 0ustar0000000000000000{- FogIndex.hs (adapted from fogindex.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program draws 5 wireframe spheres, each at a different z distance from the eye, in linear fog. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT -- Initialize color map and fog. Set screen clear color to end of color ramp. numColors, rampStart :: GLint numColors = 32 rampStart = 16 myInit :: IO () myInit = do depthFunc $= Just Less flip mapM_ [ 0 .. numColors - 1 ] $ \i -> do let shade = fromIntegral (numColors - i) / fromIntegral numColors colorMapEntry (Index1 (rampStart + i)) $= Color3 shade shade shade fog $= Enabled fogMode $= Linear 1 6 fogIndex $= Index1 numColors hint Fog $= Nicest clearIndex $= Index1 (fromIntegral (numColors + rampStart - 1)) renderSpehere :: Vector3 GLfloat -> IO () renderSpehere xyz = preservingMatrix $ do translate xyz renderObject Wireframe (Sphere' 0.4 16 16) -- display draws 5 spheres at different z positions. display :: DisplayCallback display = do clear [ ColorBuffer, DepthBuffer ] index (Index1 rampStart) mapM_ renderSpehere [ Vector3 x (-0.5) (-3 - x) | x <- [-2 .. 2] ] flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho (-2.5) 2.5 (-2.5*hf/wf) (2.5*hf/wf) (-10.0) 10.0 else ortho (-2.5*wf/hf) (2.5*wf/hf) (-2.5) 2.5 (-10.0) 10.0 matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () -- Main Loop: Open window with initial window size, title bar, color index -- display mode, depth buffer, and handle input events. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, IndexMode, WithDepthBuffer ] initialWindowSize $= Size 500 500 _ <- createWindow progName myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard displayCallback $= display mainLoop GLUT-2.7.0.16/examples/RedBook4/FogCoord.hs0000644000000000000000000000727313255126367016216 0ustar0000000000000000{- FogCoord.hs (adapted from fogcoord.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates the use of explicit fog coordinates. You can press the keyboard and change the fog coordinate value at any vertex. You can also switch between using explicit fog coordinates and the default fog generation mode. Pressing the 'f' and 'b' keys move the viewer forward and backwards. Pressing 'c' initiates the default fog generation. Pressing capital 'C' restores explicit fog coordinates. Pressing '1', '2', '3', '8', '9', and '0' add or subtract from the fog coordinate values at one of the three vertices of the triangle. -} import Control.Monad ( when ) import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { f1, f2, f3 :: IORef (FogCoord1 GLfloat) } makeState :: IO State makeState = do f1' <- newIORef (FogCoord1 1) f2' <- newIORef (FogCoord1 5) f3' <- newIORef (FogCoord1 10) return $ State { f1 = f1', f2 = f2', f3 = f3' } -- Initialize fog myInit :: IO () myInit = do let theFogColor = Color4 0 0.25 0.25 1 fog $= Enabled fogMode $= Exp 0.25 fogColor $= theFogColor hint Fog $= DontCare fogCoordSrc $= FogCoord clearColor $= theFogColor drawTriangle :: State -> (State -> IORef (FogCoord1 GLfloat)) -> Vertex3 GLfloat -> IO () drawTriangle state f v = do fc <- get (f state) fogCoord fc vertex v -- display draws a triangle at an angle. display :: State -> DisplayCallback display state = do clear [ ColorBuffer ] color (Color3 1 0.75 (0 :: GLfloat)) renderPrimitive Triangles $ do drawTriangle state f1 (Vertex3 2 (-2) 0 ) drawTriangle state f2 (Vertex3 (-2) 0 (-5)) drawTriangle state f3 (Vertex3 0 2 (-10)) swapBuffers reshape :: ReshapeCallback reshape size = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 45 1 0.25 25 matrixMode $= Modelview 0 loadIdentity translate (Vector3 0 0 (-5 :: GLfloat)) keyboard :: State -> KeyboardMouseCallback keyboard state (Char c) Down _ _ = case c of 'c' -> setSrc FragmentDepth 'C' -> setSrc FogCoord '1' -> inc f1 0.25 '2' -> inc f2 0.25 '3' -> inc f3 0.25 '8' -> inc f1 (-0.25) '9' -> inc f2 (-0.25) '0' -> inc f3 (-0.25) 'b' -> trans (-0.25) 'f' -> trans 0.25 '\27' -> exitWith ExitSuccess _ -> return () where setSrc :: FogCoordSrc -> IO () setSrc s = do fogCoordSrc $= s postRedisplay Nothing inc :: (State -> IORef (FogCoord1 GLfloat)) -> GLfloat -> IO () inc f x = do FogCoord1 oldValue <- get (f state) let newValue = oldValue + x when (newValue > 0) $ do f state $= FogCoord1 newValue postRedisplay Nothing trans :: GLfloat -> IO () trans x = do matrixMode $= Modelview 0 translate (Vector3 0 0 x) postRedisplay Nothing keyboard _ _ _ _ _ = return () -- Main Loop: Open window with initial window size, title bar, RGBA display -- mode, and handle input events. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ DoubleBuffered, RGBMode ] initialWindowSize $= Size 500 500 _ <- createWindow progName state <- makeState myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard state) displayCallback $= display state mainLoop GLUT-2.7.0.16/examples/RedBook4/Fog.hs0000644000000000000000000000563413255126367015226 0ustar0000000000000000{- Fog.hs (adapted from fog.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program draws 5 red spheres, each at a different z distance from the eye, in different types of fog. Pressing the f key chooses between 3 types of fog: exponential, exponential squared, and linear. In this program, there is a fixed density value, as well as fixed start and end values for the linear fog. -} import Data.Char ( toLower ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT myInit :: IO () myInit = do depthFunc $= Just Less position (Light 0) $= Vertex4 0.5 0.5 3.0 0.0 lighting $= Enabled light (Light 0) $= Enabled -- NOTE: The alpha values are missing from fog.c! materialAmbient Front $= Color4 0.1745 0.01175 0.01175 1.0 materialDiffuse Front $= Color4 0.61424 0.04136 0.04136 1.0 materialSpecular Front $= Color4 0.727811 0.626959 0.626959 1.0 materialShininess Front $= 0.6 * 128 fog $= Enabled let c = Color4 0.5 0.5 0.5 1.0 fogMode $= Exp 0.35 fogColor $= c hint Fog $= DontCare clearColor $= c renderSpehere :: Vector3 GLfloat -> IO () renderSpehere xyz = preservingMatrix $ do translate xyz renderObject Solid (Sphere' 0.4 16 16) -- display draws 5 spheres at different z positions. display :: DisplayCallback display = do clear [ ColorBuffer, DepthBuffer ] mapM_ renderSpehere [ Vector3 x (-0.5) (-3 - x) | x <- [-2 .. 2] ] flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho (-2.5) 2.5 (-2.5*hf/wf) (2.5*hf/wf) (-10.0) 10.0 else ortho (-2.5*wf/hf) (2.5*wf/hf) (-2.5) 2.5 (-10.0) 10.0 matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char c) Down _ _ = case toLower c of 'f' -> do mode <- get fogMode case mode of Linear _ _ -> do fogMode $= Exp 0.35; putStrLn "Fog mode is Exp" Exp _ -> do fogMode $= Exp2 0.35; putStrLn "Fog mode is Exp2" Exp2 _ -> do fogMode $= Linear 1 5; putStrLn "Fog mode is Linear" postRedisplay Nothing '\27' -> exitWith ExitSuccess _ -> return () keyboard _ _ _ _ = return () -- Main Loop: Open window with initial window size, title bar, RGBA display -- mode, depth buffer, and handle input events. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 500 500 _ <- createWindow progName myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard displayCallback $= display mainLoop GLUT-2.7.0.16/examples/RedBook4/Feedback.hs0000644000000000000000000000464113255126367016174 0ustar0000000000000000{- Feedback.hs (adapted from feedback.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates use of OpenGL feedback. First, a lighting environment is set up and a few lines are drawn. Then feedback mode is entered, and the same lines are drawn. The results in the feedback buffer are printed. -} import Control.Monad ( when ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT -- Initialize lighting. myInit :: IO () myInit = do lighting $= Enabled light (Light 0) $= Enabled -- Draw a few lines and two points, one of which will be clipped. If in feedback -- mode, a passthrough token is issued between each primitive drawGeometry :: IO () drawGeometry = do mode <- get renderMode -- resolve overloading, not needed in "real" programs let normal3f = normal :: Normal3 GLfloat -> IO () vertex3f = vertex :: Vertex3 GLfloat -> IO () renderPrimitive LineStrip $ do normal3f (Normal3 0 0 1) vertex3f (Vertex3 30 30 0) vertex3f (Vertex3 50 60 0) vertex3f (Vertex3 70 40 0) when (mode == Feedback) $ passThrough (PassThroughValue 1) renderPrimitive Points $ vertex3f (Vertex3 (-100) (-100) (-100)) -- will be clipped when (mode == Feedback) $ passThrough (PassThroughValue 2) renderPrimitive Points $ do normal3f (Normal3 0 0 1) vertex3f (Vertex3 50 50 0) flush -- not in original example printBuffer :: Maybe [FeedbackToken] -> IO () printBuffer = maybe (putStrLn "feedback buffer overflow") (mapM_ print) display :: DisplayCallback display = do matrixMode $= Projection loadIdentity ortho 0 100 0 100 0 1 clearColor $= Color4 0 0 0 0 clear [ ColorBuffer ] drawGeometry (_, tokens) <- getFeedbackTokens 1024 ThreeDColor drawGeometry printBuffer tokens keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 100 100 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit displayCallback $= display keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/DrawF.hs0000644000000000000000000000372713255126367015517 0ustar0000000000000000{- DrawF.hs (adapted from drawf.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE Draws the bitmapped letter F on the screen (several times). This demonstrates use of the bitmap call. -} import Foreign ( Ptr, newArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT myInit :: IO (Ptr GLubyte) myInit = do rowAlignment Unpack $= 1 clearColor $= Color4 0 0 0 0 newArray [ 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xff, 0x00, 0xff, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xff, 0xc0, 0xff, 0xc0 ] display :: Ptr GLubyte -> DisplayCallback display rasters = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () rasterPos2i = rasterPos :: Vertex2 GLint -> IO () color3f (Color3 1 1 1) rasterPos2i (Vertex2 20 20) sequence_ $ replicate 3 $ bitmap (Size 10 12) (Vertex2 0 0) (Vector2 11 0) rasters flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho 0 (fromIntegral w) 0 (fromIntegral h) (-1) 1 matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () -- Main Loop -- Open window with initial window size, title bar, -- RGBA display mode, and handle input events. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 100 100 initialWindowPosition $= Position 100 100 _ <- createWindow progName rasters <- myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard displayCallback $= display rasters mainLoop GLUT-2.7.0.16/examples/RedBook4/Double.hs0000644000000000000000000000431613255126367015721 0ustar0000000000000000{- Double.hs (adapted from double.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This is a simple double buffered program. Pressing the left mouse button rotates the rectangle. Pressing the middle mouse button stops the rotation. -} import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { spin :: IORef GLfloat } makeState :: IO State makeState = do s <- newIORef 0 return $ State { spin = s } display :: State -> DisplayCallback display state = do clear [ ColorBuffer ] preservingMatrix $ do s <- get (spin state) rotate s (Vector3 0 0 1) color (Color3 1 1 1 :: Color3 GLfloat) rect (Vertex2 (-25) (-25)) (Vertex2 25 25 :: Vertex2 GLfloat) swapBuffers spinDisplay :: State -> IdleCallback spinDisplay state = do let wrap n s = if s > n then s - n else s spin state $~ (wrap 360 . (+ 2)) postRedisplay Nothing myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat reshape :: ReshapeCallback reshape size = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho (-50) 50 (-50) 50 (-1) 1 matrixMode $= Modelview 0 loadIdentity keyboardMouse :: State -> KeyboardMouseCallback keyboardMouse state (MouseButton b) Down _ _ = idleCallback $= case b of LeftButton -> Just (spinDisplay state) _ -> Nothing -- ESC not handled in the original example, but useful nevertheless keyboardMouse _ (Char '\27') Down _ _ = exitWith ExitSuccess keyboardMouse _ _ _ _ _ = return () -- Request double buffer display mode. -- Register mouse input callback functions main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ DoubleBuffered, RGBMode ] initialWindowSize $= Size 250 250 initialWindowPosition $= Position 100 100 _ <- createWindow progName state <- makeState myInit displayCallback $= display state reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboardMouse state) mainLoop GLUT-2.7.0.16/examples/RedBook4/DOF.hs0000644000000000000000000001624713255126367015125 0ustar0000000000000000{- DOF.hs (adapted from dof.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates use of the accumulation buffer to create an out-of-focus depth-of-field effect. The teapots are drawn several times into the accumulation buffer. The viewing volume is jittered, except at the focal point, where the viewing volume is at the same position, each time. In this case, the gold teapot remains in focus. -} import Data.List ( genericLength ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT -- j8 contains values in the range -.5 < x < .5, -.5 < y < .5, and have a -- gaussian distribution around the origin. Use these to do model jittering for -- scene anti-aliasing and view volume jittering for depth of field effects. Use -- in conjunction with the accwindow routine. j8 :: [Vector2 GLdouble] j8 = [ Vector2 (-0.334818) 0.435331 , Vector2 0.286438 (-0.393495), Vector2 0.459462 0.141540 , Vector2 (-0.414498) (-0.192829), Vector2 (-0.183790) 0.082102 , Vector2 (-0.079263) (-0.317383), Vector2 0.102254 0.299133 , Vector2 0.164216 (-0.054399) ] -- The first 6 arguments are identical to the frustum call. pixD is anti-alias -- jitter in pixels. Use (Vector2 0 0) for no anti-alias jitter. eyeD is -- depth-of field jitter in pixels. Use (Vector2 0 0) for no depth of field -- effects. focus is distance from eye to plane in focus. focus must be greater -- than, but not equal to 0. Note that accFrustum calls translate. You will -- probably want to insure that your ModelView matrix has been initialized to -- identity before calling accFrustum. accFrustum :: GLdouble -> GLdouble -> GLdouble -> GLdouble -> GLdouble -> GLdouble -> Vector2 GLdouble -> Vector2 GLdouble -> GLdouble -> IO () accFrustum left right bottom top zNear zFar (Vector2 pixDx pixDy) (Vector2 eyeDx eyeDy) focus = do (_, Size w h) <- get viewport let xWSize = right - left; yWSize = top - bottom; dx = -(pixDx * xWSize / fromIntegral w + eyeDx * zNear / focus) dy = -(pixDy * yWSize / fromIntegral h + eyeDy * zNear / focus) matrixMode $= Projection loadIdentity frustum (left + dx) (right + dx) (bottom + dy) (top + dy) zNear zFar matrixMode $= Modelview 0 loadIdentity translate (Vector3 (-eyeDx) (-eyeDy) 0) -- The first 4 arguments are identical to the perspective call. pixD is -- anti-alias jitter in pixels. Use (Vector2 0 0) for no anti-alias jitter. eyeD -- is depth-of field jitter in pixels. Use (Vector2 0 0) for no depth of field -- effects. focus is distance from eye to plane in focus. focus must be greater -- than, but not equal to 0. Note that accPerspective calls accFrustum. accPerspective :: GLdouble -> GLdouble -> GLdouble -> GLdouble -> Vector2 GLdouble -> Vector2 GLdouble -> GLdouble -> IO () accPerspective fovY aspect zNear zFar pixD eyeD focus = do let fov2 = ((fovY * pi) / 180) / 2 top = zNear / (cos fov2 / sin fov2) bottom = -top right = top * aspect left = -right accFrustum left right bottom top zNear zFar pixD eyeD focus myInit :: IO DisplayList myInit = do ambient (Light 0) $= Color4 0 0 0 1 diffuse (Light 0) $= Color4 1 1 1 1 position (Light 0) $= Vertex4 0 3 3 0 lightModelAmbient $= Color4 0.2 0.2 0.2 1 lightModelLocalViewer $= Disabled frontFace $= CW lighting $= Enabled light (Light 0) $= Enabled autoNormal $= Enabled normalize $= Enabled depthFunc $= Just Less clearColor $= Color4 0 0 0 0 clearAccum $= Color4 0 0 0 0 -- make teapot display list defineNewList Compile $ renderObject Solid (Teapot 0.5) -- Move object into position, specify the material properties, draw a teapot. renderTeapot :: DisplayList -> Vector3 GLfloat -> Color4 GLfloat -> Color4 GLfloat -> Color4 GLfloat -> GLfloat -> IO () renderTeapot teapotList pos amb dif spec shine = preservingMatrix $ do translate pos materialAmbient Front $= amb materialDiffuse Front $= dif materialSpecular Front $= spec materialShininess Front $= shine * 128 callList teapotList -- display draws 5 teapots into the accumulation buffer several times; each time -- with a jittered perspective. The focal point is at z = 5.0, so the gold -- teapot will stay in focus. The amount of jitter is adjusted by the magnitude -- of the accPerspective jitter; in this example, 0.33. In this example, the -- teapots are drawn 8 times. display :: DisplayList -> DisplayCallback display teapotList = do (_, Size w h) <- get viewport clear [ AccumBuffer ] flip mapM_ j8 $ \(Vector2 x y) -> do clear [ ColorBuffer, DepthBuffer ] accPerspective 45 (fromIntegral w / fromIntegral h) 1 15 (Vector2 0 0) (Vector2 (0.33 * x) (0.33 * y)) 5 -- ruby, gold, silver, emerald, and cyan teapots renderTeapot teapotList (Vector3 (-1.1) (-0.5) (-4.5)) (Color4 0.1745 0.01175 0.01175 1) (Color4 0.61424 0.04136 0.04136 1) (Color4 0.727811 0.626959 0.626959 1) 0.6 renderTeapot teapotList (Vector3 (-0.5) (-0.5) (-5.0)) (Color4 0.24725 0.1995 0.0745 1) (Color4 0.75164 0.60648 0.22648 1) (Color4 0.628281 0.555802 0.366065 1) 0.4 renderTeapot teapotList (Vector3 0.2 (-0.5) (-5.5)) (Color4 0.19225 0.19225 0.19225 1) (Color4 0.50754 0.50754 0.50754 1) (Color4 0.508273 0.508273 0.508273 1) 0.4 renderTeapot teapotList (Vector3 1.0 (-0.5) (-6.0)) (Color4 0.0215 0.1745 0.0215 1) (Color4 0.07568 0.61424 0.07568 1) (Color4 0.633 0.727811 0.633 1) 0.6 renderTeapot teapotList (Vector3 1.8 (-0.5) (-6.5)) (Color4 0.0 0.1 0.06 1) (Color4 0.0 0.50980392 0.50980392 1) (Color4 0.50196078 0.50196078 0.50196078 1) 0.25 accum Accum (recip (genericLength j8)) accum Return 1 flush reshape :: ReshapeCallback reshape size = do viewport $= (Position 0 0, size) keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () -- Main Loop: Be certain you request an accumulation buffer. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithAccumBuffer, WithDepthBuffer ] initialWindowSize $= Size 400 400 initialWindowPosition $= Position 100 100 _ <- createWindow progName teapotList <- myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard displayCallback $= display teapotList mainLoop GLUT-2.7.0.16/examples/RedBook4/DList.hs0000644000000000000000000000544613255126367015533 0ustar0000000000000000{- DList.hs (adapted from list.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates how to make and execute a display list. Note that attributes, such as current color and matrix, are changed. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT myInit :: IO DisplayList myInit = do listName <- genObjectName -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () vertex2f = vertex :: Vertex2 GLfloat -> IO () translatef = translate :: Vector3 GLfloat -> IO () defineList listName Compile $ do color3f (Color3 1 0 0) -- current color red renderPrimitive Triangles $ do vertex2f (Vertex2 0 0) vertex2f (Vertex2 1 0) vertex2f (Vertex2 0 1) translatef (Vector3 1.5 0.0 0.0) -- move position shadeModel $= Flat return listName drawLine :: IO () drawLine = do -- resolve overloading, not needed in "real" programs let vertex2f = vertex :: Vertex2 GLfloat -> IO () renderPrimitive Lines $ do vertex2f (Vertex2 0.0 0.5) vertex2f (Vertex2 15.0 0.5) display :: DisplayList -> DisplayCallback display listName = do -- NOTE: The following 'loadIdentity' is missing in the original -- example, but without it the translatef calls accumulate and -- the graphics wander out of the window after a few redraws... loadIdentity clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () color3f (Color3 0 1 0) -- current color green sequence_ (replicate 10 (callList listName)) -- draw 10 triangles drawLine -- is this line green? NO! -- where is the line drawn? flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho2D 0.0 2.0 (-0.5*hf/wf) (1.5*hf/wf) else ortho2D 0.0 (2.0*wf/hf) (-0.5) 1.5 matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () -- Open window with initial window size, title bar, -- RGBA display mode, and handle input events. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 650 50 _ <- createWindow progName listName <- myInit reshapeCallback $= Just reshape displayCallback $= display listName keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/CubeMap.hs0000644000000000000000000000743513255126367016030 0ustar0000000000000000{- CubeMap.hs (adapted from CubeMap.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates cube map textures. Six different colored checker board textures are created and applied to a lit sphere. Pressing the 'f' and 'b' keys translate the viewer forward and backward. -} import Data.Bits ( (.&.) ) import Data.IORef ( IORef, newIORef ) import Foreign ( withArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { zTrans :: IORef GLfloat } makeState :: IO State makeState = do z <- newIORef 0 return $ State { zTrans = z } imageSize :: TextureSize2D imageSize = TextureSize2D 4 4 withCheckImage :: TextureSize2D -> GLsizei -> (GLubyte -> (Color4 GLubyte)) -> (PixelData (Color4 GLubyte) -> IO ()) -> IO () withCheckImage (TextureSize2D w h) n f act = withArray [ f c | i <- [ 0 .. w - 1 ], j <- [ 0 .. h - 1 ], let c | (i .&. n) == (j .&. n) = 0 | otherwise = 255 ] $ act. PixelData RGBA UnsignedByte makeImage :: TextureTargetCubeMapFace -> (GLubyte -> (Color4 GLubyte)) -> IO () makeImage target f = withCheckImage imageSize 0x1 f $ texImage2D target NoProxy 0 RGBA' imageSize 0 myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 depthFunc $= Just Less shadeModel $= Smooth rowAlignment Unpack $= 1 textureWrapMode TextureCubeMap S $= (Repeated, Repeat) textureWrapMode TextureCubeMap T $= (Repeated, Repeat) textureWrapMode TextureCubeMap R $= (Repeated, Repeat) textureFilter TextureCubeMap $= ((Nearest, Nothing), Nearest) makeImage TextureCubeMapPositiveX (\c -> Color4 c c c 255) makeImage TextureCubeMapNegativeX (\c -> Color4 0 c c 255) makeImage TextureCubeMapPositiveY (\c -> Color4 c c 0 255) makeImage TextureCubeMapNegativeY (\c -> Color4 255 c c 255) makeImage TextureCubeMapPositiveZ (\c -> Color4 c 0 c 255) makeImage TextureCubeMapNegativeZ (\c -> Color4 c c 255 255) textureGenMode S $= Just NormalMap textureGenMode T $= Just NormalMap textureGenMode R $= Just NormalMap textureFunction $= Modulate texture TextureCubeMap $= Enabled lighting $= Enabled light (Light 0) $= Enabled autoNormal $= Enabled normalize $= Enabled materialDiffuse Front $= Color4 1 1 1 1 display :: State -> DisplayCallback display state = do clear [ ColorBuffer, DepthBuffer ] preservingMatrix $ do z <- get (zTrans state) translate (Vector3 0 0 z) renderObject Solid (Sphere' 5 20 10) swapBuffers reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 40 (fromIntegral w / fromIntegral h) 1 300 matrixMode $= Modelview 0 loadIdentity translate (Vector3 0 0 (-20 :: GLfloat)) keyboard :: State -> KeyboardMouseCallback keyboard state (Char 'f') Down _ _ = move state (-0.2) keyboard state (Char 'b') Down _ _ = move state 0.2 keyboard _ (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ _ = return () move :: State -> GLfloat -> IO () move state inc = do zTrans state $~ (+ inc) postRedisplay Nothing main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ DoubleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 400 400 initialWindowPosition $= Position 50 50 _ <- createWindow progName state <- makeState myInit displayCallback $= display state reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard state) mainLoop GLUT-2.7.0.16/examples/RedBook4/Cube.hs0000644000000000000000000000326713255126367015371 0ustar0000000000000000{- Cube.hs (adapted from cube.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates a single modeling transformation, scale and a single viewing transformation, lookAt. A wireframe cube is rendered. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat display :: DisplayCallback display = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () scalef = scale :: GLfloat -> GLfloat -> GLfloat -> IO () color3f (Color3 1 1 1) loadIdentity -- clear the matrix -- viewing transformation lookAt (Vertex3 0 0 5) (Vertex3 0 0 0) (Vector3 0 1 0) scalef 1 2 1 -- modeling transformation renderObject Wireframe (Cube 1) flush reshape :: ReshapeCallback reshape size = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity frustum (-1) 1 (-1) 1 1.5 20 matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit displayCallback $= display reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/Convolution.hs0000644000000000000000000000526613255126367017033 0ustar0000000000000000{- Convolution.hs (adapted from convolution.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE Use various 2D convolutions filters to find edges in an image. -} import Foreign ( withArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT import ReadImage data Filter = Filter String [GLfloat] filterTable :: [(Key,Filter)] filterTable = [ (Char 'h', Filter "horizontal" [ 0, -1, 0, 0, 1, 0, 0, 0, 0 ]), (Char 'v', Filter "vertical" [ 0, 0, 0, -1, 1, 0, 0, 0, 0 ]), (Char 'l', Filter "laplacian" [ -0.125, -0.125, -0.125, -0.125, 1.0 , -0.125, -0.125, -0.125, -0.125 ])] setFilter :: Filter -> IO () setFilter (Filter filterName filterData) = do putStrLn ("Using the " ++ filterName ++ " filter") withArray filterData $ \buf -> convolutionFilter2D Luminance' (Size 3 3) (PixelData Luminance Float buf) myInit :: IO () myInit = do rowAlignment Unpack $= 1 clearColor $= Color4 0 0 0 0 setFilter (snd (head filterTable)) convolution Convolution2D $= Enabled display :: Size -> PixelData a -> DisplayCallback display size pixels = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let rasterPos2i = rasterPos :: Vertex2 GLint -> IO () rasterPos2i (Vertex2 1 1) drawPixels size pixels flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho 0 (fromIntegral w) 0 (fromIntegral h) (-1) 1 matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard key Down _ _ = maybe (return ()) (\f -> do setFilter f; postRedisplay Nothing) (lookup key filterTable) keyboard _ _ _ _ = return () -- Main Loop: Open window with initial window size, title bar, RGBA display -- mode, and handle input events. main :: IO () main = do (progName, args) <- getArgsAndInitialize (size, pixels) <- readImage (if null args then "Data/leeds.bin" else head args) initialDisplayMode $= [ SingleBuffered, RGBAMode ] initialWindowSize $= size initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard displayCallback $= display size pixels mainLoop GLUT-2.7.0.16/examples/RedBook4/Combiner.hs0000644000000000000000000001565013255126367016250 0ustar0000000000000000{- Combiner.hs (adapted from combiner.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program renders a variety of quads showing different effects of texture combiner functions. The first row renders an untextured polygon (so you can compare the fragment colors) and then the 2 textures. The second row shows several different combiner functions on a single texture: replace, modulate, add, add-signed, and subtract. The third row shows the interpolate combiner function on a single texture with a constant color/alpha value, varying the amount of interpolation. The fourth row uses multitexturing with two textures and different combiner functions. The fifth row are some combiner experiments: using the scaling factor and reversing the order of subtraction for a combination function. -} import Data.Bits ( (.&.) ) import Foreign ( withArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT -- Create checkerboard image imageSize :: TextureSize2D imageSize = TextureSize2D 8 8 makeImage :: TextureSize2D -> (GLsizei -> GLsizei -> Color4 GLubyte) -> (PixelData (Color4 GLubyte) -> IO ()) -> IO () makeImage (TextureSize2D w h) f act = withArray [ f i j | i <- [ 0 .. w - 1 ], j <- [ 0 .. h - 1 ] ] $ act . PixelData RGBA UnsignedByte myInit :: IO (TextureObject, TextureObject, DisplayList) myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Smooth rowAlignment Unpack $= 1 [texName0, texName1] <- genObjectNames 2 textureBinding Texture2D $= Just texName0 textureWrapMode Texture2D S $= (Repeated, Repeat) textureWrapMode Texture2D T $= (Repeated, Repeat) textureFilter Texture2D $= ((Nearest, Nothing), Nearest) -- horiz b & w stripes makeImage imageSize (\i _ -> let c = if i .&. 2 == 0 then 255 else 0 in Color4 c c c 255) $ texImage2D Texture2D NoProxy 0 RGBA' imageSize 0 textureBinding Texture2D $= Just texName1 textureWrapMode Texture2D S $= (Repeated, Repeat) textureWrapMode Texture2D T $= (Repeated, Repeat) textureFilter Texture2D $= ((Nearest, Nothing), Nearest) textureFunction $= Decal -- wider vertical 50% cyan and black stripes makeImage imageSize (\_ j -> let c = if j .&. 4 /= 0 then 128 else 0 in Color4 0 c c 255) $ texImage2D Texture2D NoProxy 0 RGBA' imageSize 0 -- smooth-shaded polygon with multiple texture coordinates let vert :: TexCoord2 GLfloat -> Color3 GLfloat -> Vertex3 GLfloat -> IO () vert t c v = do multiTexCoord (TextureUnit 0) t multiTexCoord (TextureUnit 1) t color c vertex v dl <- defineNewList Compile $ renderPrimitive Quads $ do vert (TexCoord2 0 0) (Color3 0.5 1 0.25) (Vertex3 0 0 0) vert (TexCoord2 0 2) (Color3 1 1 1 ) (Vertex3 0 1 0) vert (TexCoord2 2 2) (Color3 1 1 1 ) (Vertex3 1 1 0) vert (TexCoord2 2 0) (Color3 1 0.5 0.25) (Vertex3 1 0 0) return (texName0, texName1, dl) display :: (TextureObject, TextureObject, DisplayList) -> DisplayCallback display (texName0, texName1, dl) = do clear [ ColorBuffer ] let drawAt :: GLfloat -> GLfloat -> IO () drawAt x y = preservingMatrix $ do translate (Vector3 x y 0) callList dl -- untextured polygon -- see the "fragment" colors texture Texture2D $= Disabled drawAt 0 5 texture Texture2D $= Enabled -- draw ordinary textured polys; 1 texture unit; combine mode disabled textureFunction $= Modulate textureBinding Texture2D $= Just texName0 drawAt 1 5 textureBinding Texture2D $= Just texName1 drawAt 2 5 -- different combine modes enabled; 1 texture unit -- defaults are: -- argRGB Arg0 $= Arg SrcColor CurrentUnit -- argRGB Arg1 $= Arg SrcColor Previous textureBinding Texture2D $= Just texName0 textureFunction $= Combine combineRGB $= Replace' argRGB Arg0 $= Arg SrcColor CurrentUnit drawAt 1 4 combineRGB $= Modulate' argRGB Arg1 $= Arg SrcColor Previous drawAt 2 4 combineRGB $= AddUnsigned' drawAt 3 4 combineRGB $= AddSigned drawAt 4 4 combineRGB $= Subtract drawAt 5 4 -- interpolate combine with constant color; 1 texture unit -- use different alpha values for constant color -- defaults are: -- argRGB Arg0 $= Arg SrcColor CurrentUnit -- argRGB Arg1 $= Arg SrcColor Previous -- argRGB Arg2 $= Arg SrcAlpha Constant constantColor $= Color4 0 0 0 0.2 textureBinding Texture2D $= Just texName0 textureFunction $= Combine combineRGB $= Interpolate argRGB Arg0 $= Arg SrcColor CurrentUnit argRGB Arg1 $= Arg SrcColor Previous argRGB Arg2 $= Arg SrcAlpha Constant drawAt 1 3 constantColor $= Color4 0 0 0 0.4 drawAt 2 3 constantColor $= Color4 0 0 0 0.6 drawAt 3 3 constantColor $= Color4 0 0 0 0.8 drawAt 4 3 -- combine textures 0 & 1 -- defaults are: -- argRGB Arg0 $= Arg SrcColor CurrentUnit -- argRGB Arg1 $= Arg SrcColor Previous activeTexture $= TextureUnit 0 texture Texture2D $= Enabled textureBinding Texture2D $= Just texName0 textureFunction $= Modulate activeTexture $= TextureUnit 1 texture Texture2D $= Enabled textureBinding Texture2D $= Just texName1 textureFunction $= Combine combineRGB $= Replace' drawAt 1 2 -- try different combiner modes of texture unit 1 combineRGB $= Modulate' drawAt 2 2 combineRGB $= AddUnsigned' drawAt 3 2 combineRGB $= AddSigned drawAt 4 2 combineRGB $= Subtract drawAt 5 2 -- some experiments -- see the effect of rgbScale rgbScale $= 2 combineRGB $= Replace' drawAt 1 1 combineRGB $= Modulate' drawAt 2 1 rgbScale $= 1 -- reverse the order of subtraction Arg1-Arg0 textureFunction $= Combine combineRGB $= Subtract argRGB Arg0 $= Arg SrcColor Previous argRGB Arg1 $= Arg SrcColor CurrentUnit drawAt 5 1 activeTexture $= TextureUnit 1 -- deactivate multitexturing texture Texture2D $= Disabled activeTexture $= TextureUnit 0 -- activate single texture unit flush reshape :: ReshapeCallback reshape size = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho2D 0 7 0 7 matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 400 400 initialWindowPosition $= Position 100 100 _ <- createWindow progName texNamesAndDL <- myInit displayCallback $= display texNamesAndDL reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/ColorTable.hs0000644000000000000000000000403113255126367016527 0ustar0000000000000000{- ColorTable.hs (adapted from colortable.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE Invert a passed block of pixels. This program illustrates the use of the colorTable function. -} import Foreign ( withArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT import ReadImage myInit :: IO () myInit = do rowAlignment Unpack $= 1 clearColor $= Color4 0 0 0 0 -- Set up an inverse color table let tableSize = 256 t = fromIntegral (tableSize - 1) :: GLubyte withArray [ Color3 i i i | i <- [ t, t - 1 .. 0 ] ] $ \buf -> colorTable NoProxy ColorTable RGB' tableSize (PixelData RGB UnsignedByte buf) colorTableStage ColorTableStage $= Enabled display :: Size -> PixelData a -> DisplayCallback display size pixels = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let rasterPos2i = rasterPos :: Vertex2 GLint -> IO () rasterPos2i (Vertex2 1 1) drawPixels size pixels flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho 0 (fromIntegral w) 0 (fromIntegral h) (-1) 1 matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () -- Main Loop: Open window with initial window size, title bar, RGBA display -- mode, and handle input events. main :: IO () main = do (progName, args) <- getArgsAndInitialize (size, pixels) <- readImage (if null args then "Data/leeds.bin" else head args) initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= size initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard displayCallback $= display size pixels mainLoop GLUT-2.7.0.16/examples/RedBook4/ColorMatrix.hs0000644000000000000000000000400613255126367016746 0ustar0000000000000000{- ColorMatrix.hs (adapted from colormatrix.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program uses the color matrix to exchange the color channels of an image. Red -> Green Green -> Blue Blue -> Red -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT import ReadImage myInit :: IO () myInit = do m <- newMatrix ColumnMajor [ 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1 ] rowAlignment Unpack $= 1 clearColor $= Color4 0 0 0 0 matrixMode $= Color matrix Nothing $= (m :: GLmatrix GLfloat) matrixMode $= Modelview 0 display :: Size -> PixelData a -> DisplayCallback display size pixels = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let rasterPos2i = rasterPos :: Vertex2 GLint -> IO () rasterPos2i (Vertex2 1 1) drawPixels size pixels flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho 0 (fromIntegral w) 0 (fromIntegral h) (-1) 1 matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () -- Main Loop: Open window with initial window size, title bar, RGBA display -- mode, and handle input events. main :: IO () main = do (progName, args) <- getArgsAndInitialize (size, pixels) <- readImage (if null args then "Data/leeds.bin" else head args) initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= size initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard displayCallback $= display size pixels mainLoop GLUT-2.7.0.16/examples/RedBook4/ColorMat.hs0000644000000000000000000000546013255126367016230 0ustar0000000000000000{- Light.hs (adapted from light.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE After initialization, the program will be in ColorMaterial mode. Interaction: pressing the mouse buttons will change the diffuse reflection values. -} import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { r, g, b :: IORef GLfloat } diffuseMaterial :: State -> IO (Color4 GLfloat) diffuseMaterial state = do r' <- get (r state) g' <- get (g state) b' <- get (b state) return $ Color4 r' g' b' 1 makeState :: IO State makeState = do r' <- newIORef 0.5 g' <- newIORef 0.5 b' <- newIORef 0.5 return $ State { r = r', g = g', b = b' } -- Initialize material property, light source, lighting model, -- and depth buffer. myInit :: State -> IO () myInit state = do clearColor $= Color4 0 0 0 0 shadeModel $= Smooth depthFunc $= Just Less dm <- diffuseMaterial state materialDiffuse Front $= dm materialSpecular Front $= Color4 1 1 1 1 materialShininess Front $= 25 position (Light 0) $= Vertex4 1 1 1 0 lighting $= Enabled light (Light 0) $= Enabled colorMaterial $= Just (Front, Diffuse) display :: DisplayCallback display = do clear [ ColorBuffer, DepthBuffer ] renderObject Solid (Sphere' 1 20 16) flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho (-1.5) 1.5 (-1.5 * hf/wf) (1.5 * hf/wf) (-10) 10 else ortho (-1.5 * wf/hf) (1.5 * wf/hf) (-1.5) 1.5 (-10) 10 matrixMode $= Modelview 0 loadIdentity keyboardMouse :: State -> KeyboardMouseCallback keyboardMouse state (MouseButton button) Down _ _ = case button of LeftButton -> update r MiddleButton -> update g RightButton -> update b _ -> return () where update component = do component state $~ inc dm <- diffuseMaterial state color dm postRedisplay Nothing inc x = let s = x + 0.1 in if s > 1 then 0 else s keyboardMouse _ (Char '\27') Down _ _ = exitWith ExitSuccess keyboardMouse _ _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName state <- makeState myInit state displayCallback $= display reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboardMouse state) mainLoop GLUT-2.7.0.16/examples/RedBook4/Clip.hs0000644000000000000000000000346413255126367015401 0ustar0000000000000000{- Clip.hs (adapted from clip.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates arbitrary clipping planes. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat display :: DisplayCallback display = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () translatef = translate :: Vector3 GLfloat -> IO () rotatef = rotate :: GLfloat -> Vector3 GLfloat -> IO () color3f (Color3 1 1 1) preservingMatrix $ do translatef (Vector3 0 0 (-5)) -- clip lower half -- y < 0 clipPlane (ClipPlaneName 0) $= Just (Plane 0 1 0 0) -- clip left half -- x < 0 clipPlane (ClipPlaneName 1) $= Just (Plane 1 0 0 0) rotatef 90 (Vector3 1 0 0) renderObject Wireframe (Sphere' 1 20 16) flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 60 (fromIntegral w / fromIntegral h) 1 20 matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit displayCallback $= display reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/Checker.hs0000644000000000000000000000727613255126367016063 0ustar0000000000000000{- Checker.hs (adapted from checker.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program texture maps a checkerboard image onto two rectangles. Texture objects are only used when GL_EXT_texture_object is supported. -} import Control.Monad ( when ) import Data.Maybe ( isJust ) import Data.Bits ( (.&.) ) import Foreign ( withArray ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT -- Create checkerboard image checkImageSize :: TextureSize2D checkImageSize = TextureSize2D 64 64 withCheckImage :: TextureSize2D -> GLsizei -> (GLubyte -> (Color4 GLubyte)) -> (PixelData (Color4 GLubyte) -> IO ()) -> IO () withCheckImage (TextureSize2D w h) n f act = withArray [ f c | i <- [ 0 .. w - 1 ], j <- [ 0 .. h - 1 ], let c | (i .&. n) == (j .&. n) = 0 | otherwise = 255 ] $ act. PixelData RGBA UnsignedByte myInit :: IO (Maybe TextureObject) myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat depthFunc $= Just Less rowAlignment Unpack $= 1 exts <- get glExtensions mbTexName <- if "GL_EXT_texture_object" `elem` exts then fmap Just genObjectName else return Nothing when (isJust mbTexName) $ textureBinding Texture2D $= mbTexName textureWrapMode Texture2D S $= (Repeated, Repeat) textureWrapMode Texture2D T $= (Repeated, Repeat) textureFilter Texture2D $= ((Nearest, Nothing), Nearest) withCheckImage checkImageSize 0x8 (\c -> Color4 c c c 255) $ texImage2D Texture2D NoProxy 0 RGBA' checkImageSize 0 return mbTexName display :: Maybe TextureObject -> DisplayCallback display mbTexName = do clear [ ColorBuffer, DepthBuffer ] texture Texture2D $= Enabled textureFunction $= Decal when (isJust mbTexName) $ textureBinding Texture2D $= mbTexName -- resolve overloading, not needed in "real" programs let texCoord2f = texCoord :: TexCoord2 GLfloat -> IO () vertex3f = vertex :: Vertex3 GLfloat -> IO () renderPrimitive Quads $ do texCoord2f (TexCoord2 0 0); vertex3f (Vertex3 (-2.0) (-1.0) 0.0 ) texCoord2f (TexCoord2 0 1); vertex3f (Vertex3 (-2.0) 1.0 0.0 ) texCoord2f (TexCoord2 1 1); vertex3f (Vertex3 0.0 1.0 0.0 ) texCoord2f (TexCoord2 1 0); vertex3f (Vertex3 0.0 (-1.0) 0.0 ) texCoord2f (TexCoord2 0 0); vertex3f (Vertex3 1.0 (-1.0) 0.0 ) texCoord2f (TexCoord2 0 1); vertex3f (Vertex3 1.0 1.0 0.0 ) texCoord2f (TexCoord2 1 1); vertex3f (Vertex3 2.41421 1.0 (-1.41421)) texCoord2f (TexCoord2 1 0); vertex3f (Vertex3 2.41421 (-1.0) (-1.41421)) flush texture Texture2D $= Disabled reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 60 (fromIntegral w / fromIntegral h) 1 30 matrixMode $= Modelview 0 loadIdentity translate (Vector3 0 0 (-3.6 :: GLfloat)) keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 250 250 initialWindowPosition $= Position 100 100 _ <- createWindow progName mbTexName <- myInit displayCallback $= display mbTexName reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/BlendEqn.hs0000644000000000000000000000570213255126367016177 0ustar0000000000000000{- BlendEqn.hs (adapted from blendeqn.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE Demonstrate the different blending functions available with the OpenGL imaging subset. This program demonstrates use of blendEquation. The following keys change the selected blend equation function: 'a' -> FuncAdd 's' -> FuncSubtract 'r' -> FuncReverseSubtract 'm' -> Min 'x' -> Max -} import Data.Char ( toLower ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT myInit :: IO () myInit = do clearColor $= Color4 1 1 0 0 blendFunc $= (One, One) blend $= Enabled display :: DisplayCallback display = do clear [ ColorBuffer ] color (Color3 0 0 (1 :: GLfloat)) rect (Vertex2 (-0.5) (-0.5)) (Vertex2 0.5 (0.5 :: GLfloat)) flush reshape :: ReshapeCallback reshape size@(Size w h) = do let aspect = fromIntegral w / fromIntegral h viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity if aspect < 1 then let aspect' = recip aspect in ortho (-aspect') aspect' (-1) 1 (-1) 1 else ortho (-1) 1 (-aspect) aspect (-1) 1 matrixMode $= Modelview 0 keyboard :: KeyboardMouseCallback keyboard (Char c) Down _ _ = case toLower c of -- Colors are added as: (0, 0, 1) + (1, 1, 0) = (1, 1, 1) -- which will produce a white square on a yellow background. 'a' -> setBlendEquation FuncAdd -- Colors are subtracted as: (0, 0, 1) - (1, 1, 0) = (-1, -1, 1) -- which is clamped to (0, 0, 1), producing a blue square on a -- yellow background 's' -> setBlendEquation FuncSubtract -- Colors are subtracted as: (1, 1, 0) - (0, 0, 1) = (1, 1, -1) -- which is clamed to (1, 1, 0). This produces yellow for both -- the square and the background. 'r' -> setBlendEquation FuncReverseSubtract -- The minimum of each component is computed, as -- [min(0, 1), min(0, 1), min(1, 0)] which equates to (0, 0, 0). -- This will produce a black square on the yellow background. 'm' -> setBlendEquation Min -- The minimum of each component is computed, as -- [max(0, 1), max(0, 1), max(1, 0)] which equates to (1, 1, 1) -- This will produce a white square on the yellow background. 'x' -> setBlendEquation Max '\27' -> exitWith ExitSuccess _ -> return () where setBlendEquation e = do blendEquation $= e postRedisplay Nothing keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 512 512 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard displayCallback $= display mainLoop GLUT-2.7.0.16/examples/RedBook4/BezSurf.hs0000644000000000000000000000523213255126367016065 0ustar0000000000000000{- BezSurf.hs (adapted from bezsurf.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program renders a wireframe Bezier surface, using two-dimensional evaluators. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT ctrlPoints :: [[Vertex3 GLfloat]] ctrlPoints = [ [ Vertex3 (-1.5) (-1.5) 4.0, Vertex3 (-0.5) (-1.5) 2.0, Vertex3 0.5 (-1.5) (-1.0), Vertex3 1.5 (-1.5) 2.0 ], [ Vertex3 (-1.5) (-0.5) 1.0, Vertex3 (-0.5) (-0.5) 3.0, Vertex3 0.5 (-0.5) 0.0, Vertex3 1.5 (-0.5) (-1.0) ], [ Vertex3 (-1.5) 0.5 4.0, Vertex3 (-0.5) 0.5 0.0, Vertex3 0.5 0.5 3.0, Vertex3 1.5 0.5 4.0 ], [ Vertex3 (-1.5) 1.5 (-2.0), Vertex3 (-0.5) 1.5 (-2.0), Vertex3 0.5 1.5 0.0, Vertex3 1.5 1.5 (-1.0) ]] -- Hey mom, look, it's C! ;-) for :: GLfloat -> GLfloat -> (GLfloat -> IO ()) -> IO () for s e f = mapM_ f [ i | i <- [ s, if s <= e then s + 1 else s - 1 .. e ] ] display :: DisplayCallback display = do clear [ ColorBuffer, DepthBuffer ] color (Color3 1 1 1 :: Color3 GLfloat) preservingMatrix $ do rotate (85 :: GLfloat) (Vector3 1 1 1) for 0 8 $ \j -> do renderPrimitive LineStrip $ do for 0 30 $ \i -> evalCoord2 (i/30, j/ 8) renderPrimitive LineStrip $ do for 0 30 $ \i -> evalCoord2 (j/ 8, i/30) flush myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 m <- newMap2 (0, 1) (0, 1) ctrlPoints map2 $= Just (m :: GLmap2 Vertex3 GLfloat) mapGrid2 $= ((20, (0, 1)), (20, (0, 1 :: GLfloat))) depthFunc $= Just Less shadeModel $= Flat reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho (-4.0) 4.0 (-4.0*hf/wf) (4.0*hf/wf) (-4.0) 4.0 else ortho (-4.0*wf/hf) (4.0*wf/hf) (-4.0) 4.0 (-4.0) 4.0 matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit displayCallback $= display reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/BezMesh.hs0000644000000000000000000000527313255126367016047 0ustar0000000000000000{- BezMesh.hs (adapted from bezmesh.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program renders a lighted, filled Bezier surface, using two-dimensional evaluators. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Data.List ( transpose ) import Graphics.UI.GLUT ctrlPoints :: [[Vertex3 GLfloat]] ctrlPoints = [ [ Vertex3 (-1.5) (-1.5) 4.0, Vertex3 (-0.5) (-1.5) 2.0, Vertex3 0.5 (-1.5) (-1.0), Vertex3 1.5 (-1.5) 2.0 ], [ Vertex3 (-1.5) (-0.5) 1.0, Vertex3 (-0.5) (-0.5) 3.0, Vertex3 0.5 (-0.5) 0.0, Vertex3 1.5 (-0.5) (-1.0) ], [ Vertex3 (-1.5) 0.5 4.0, Vertex3 (-0.5) 0.5 0.0, Vertex3 0.5 0.5 3.0, Vertex3 1.5 0.5 4.0 ], [ Vertex3 (-1.5) 1.5 (-2.0), Vertex3 (-0.5) 1.5 (-2.0), Vertex3 0.5 1.5 0.0, Vertex3 1.5 1.5 (-1.0) ]] initlights :: IO () initlights = do lighting $= Enabled light (Light 0) $= Enabled ambient (Light 0) $= Color4 0.2 0.2 0.2 1.0 position (Light 0) $= Vertex4 0 0 2 1 materialDiffuse Front $= Color4 0.6 0.6 0.6 1.0 materialSpecular Front $= Color4 1.0 1.0 1.0 1.0 materialShininess Front $= 50 display :: DisplayCallback display = do clear [ ColorBuffer, DepthBuffer ] preservingMatrix $ do rotate (85 :: GLfloat) (Vector3 1 1 1) evalMesh2 Fill (0, 20) (0, 20) flush myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 depthFunc $= Just Less m <- newMap2 (0, 1) (0, 1) (transpose ctrlPoints) map2 $= Just (m :: GLmap2 Vertex3 GLfloat) autoNormal $= Enabled mapGrid2 $= ((20, (0, 1)), (20, (0, 1 :: GLfloat))) initlights -- for lighted version only reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho (-4.0) 4.0 (-4.0*hf/wf) (4.0*hf/wf) (-4.0) 4.0 else ortho (-4.0*wf/hf) (4.0*wf/hf) (-4.0) 4.0 (-4.0) 4.0 matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit reshapeCallback $= Just reshape displayCallback $= display keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/BezCurve.hs0000644000000000000000000000375713255126367016244 0ustar0000000000000000{- BezCurve.hs (adapted from bezcurve.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program uses evaluators to draw a Bezier curve. -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT ctrlPoints :: [Vertex3 GLfloat] ctrlPoints = [ Vertex3 (-4)(-4) 0, Vertex3 (-2) 4 0, Vertex3 2 (-4) 0, Vertex3 4 4 0 ] myInit :: IO () myInit = do clearColor $= Color4 0 0 0 0 shadeModel $= Flat m <- newMap1 (0, 1) ctrlPoints map1 $= Just (m :: GLmap1 Vertex3 GLfloat) display :: DisplayCallback display = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () color3f (Color3 1 1 1) renderPrimitive LineStrip $ mapM_ evalCoord1 [ i/30.0 :: GLfloat | i <- [0..30] ] -- The following code displays the control points as dots. pointSize $= 5 color3f (Color3 1 1 0) renderPrimitive Points $ mapM_ vertex ctrlPoints flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho (-5.0) 5.0 (-5.0*hf/wf) (5.0*hf/wf) (-5.0) 5.0 else ortho (-5.0*wf/hf) (5.0*wf/hf) (-5.0) 5.0 (-5.0) 5.0 matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit displayCallback $= display reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/Alpha3D.hs0000644000000000000000000000767513255126367015736 0ustar0000000000000000{- Alpha3D.hs (adapted from alpha3D.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates how to intermix opaque and alpha blended polygons in the same scene, by using depthMask. Press the 'a' key to animate moving the transparent object through the opaque object. Press the 'r' key to reset the scene. -} import Data.Char ( toLower ) import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT maxZ, minZ, zInc :: GLfloat maxZ = 8 minZ = -8 zInc = 0.4 -- We don't animate via the idle callback, because this is way too fast on -- modern computers. A timer with the delay below is used instead for redraw. delay :: Timeout delay = 100 data State = State { solidZ, transparentZ :: IORef GLfloat } makeState :: IO State makeState = do s <- newIORef maxZ t <- newIORef minZ return $ State { solidZ = s, transparentZ = t } data DisplayLists = DisplayLists { sphereList, cubeList :: DisplayList } myInit :: IO DisplayLists myInit = do materialSpecular Front $= Color4 1 1 1 0.15 materialShininess Front $= 100 position (Light 0) $= Vertex4 0.5 0.5 1 0 lighting $= Enabled light (Light 0) $= Enabled depthFunc $= Just Less s <- defineNewList Compile $ renderObject Solid (Sphere' 0.4 16 16) c <- defineNewList Compile $ renderObject Solid (Cube 0.6) return $ DisplayLists { sphereList = s, cubeList = c } display :: State -> DisplayLists -> DisplayCallback display state displayLists = do clear [ ColorBuffer, DepthBuffer ] preservingMatrix $ do s <- get (solidZ state) translate (Vector3 (-0.15) (-0.15) s) materialEmission Front $= Color4 0 0 0 1 materialDiffuse Front $= Color4 0.75 0.75 0 1 callList (sphereList displayLists) preservingMatrix $ do t <- get (transparentZ state) translate (Vector3 (0.15) (0.15) t) rotate (15 :: GLfloat) (Vector3 1 1 0) rotate (30 :: GLfloat) (Vector3 0 1 0) materialEmission Front $= Color4 0 0.3 0.3 0.6 materialDiffuse Front $= Color4 0 0.8 0.8 0.6 blend $= Enabled depthMask $= Disabled blendFunc $= (SrcAlpha, One) callList (cubeList displayLists) depthMask $= Enabled blend $= Disabled swapBuffers reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho (-1.5) 1.5 (-1.5*hf/wf) (1.5*hf/wf) (-10) 10 else ortho (-1.5*wf/hf) (1.5*wf/hf) (-1.5) 1.5 (-10) 10 matrixMode $= Modelview 0 loadIdentity animate :: State -> TimerCallback animate state = do s <- get (solidZ state) t <- get (transparentZ state) if (s <= minZ || t >= maxZ) then idleCallback $= Nothing else do solidZ state $~ (+ (- zInc)) transparentZ state $~ (+ zInc) addTimerCallback delay (animate state) postRedisplay Nothing keyboard :: State -> KeyboardMouseCallback keyboard state (Char c) Down _ _ = case toLower c of 'a' -> do solidZ state $= maxZ; transparentZ state $= minZ; addTimerCallback delay (animate state) 'r' -> do solidZ state $= maxZ; transparentZ state $= minZ; postRedisplay Nothing '\27' -> exitWith ExitSuccess _ -> return () keyboard _ _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize -- The original C example uses single buffering, which flickers a lot. initialDisplayMode $= [ DoubleBuffered, RGBMode, WithDepthBuffer ] initialWindowSize $= Size 500 500 _ <- createWindow progName state <- makeState displayLists <- myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard state) displayCallback $= display state displayLists mainLoop GLUT-2.7.0.16/examples/RedBook4/Alpha.hs0000644000000000000000000000530013255126367015526 0ustar0000000000000000{- Alpha.hs (adapted from alpha.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program draws several overlapping filled polygons to demonstrate the effect order has on alpha blending results. Use the 't' key to toggle the order of drawing polygons. -} import Data.Char ( toLower ) import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { leftFirst :: IORef Bool } makeState :: IO State makeState = do l <- newIORef True return $ State { leftFirst = l } -- Initialize alpha blending function. myInit :: IO () myInit = do blend $= Enabled blendFunc $= (SrcAlpha, OneMinusSrcAlpha) shadeModel $= Flat clearColor $= Color4 0 0 0 0 drawLeftTriangle :: IO () drawLeftTriangle = -- draw yellow triangle on LHS of screen renderPrimitive Triangles $ do color (Color4 1 1 0 (0.75 :: GLfloat)) vertex (Vertex3 0.1 0.9 (0 :: GLfloat)) vertex (Vertex3 0.1 0.1 (0 :: GLfloat)) vertex (Vertex3 0.7 0.5 (0 :: GLfloat)) drawRightTriangle :: IO () drawRightTriangle = -- draw cyan triangle on RHS of screen renderPrimitive Triangles $ do color (Color4 0 1 1 (0.75 :: GLfloat)) vertex (Vertex3 0.9 0.9 (0 :: GLfloat)) vertex (Vertex3 0.3 0.5 (0 :: GLfloat)) vertex (Vertex3 0.9 0.1 (0 :: GLfloat)) display :: State -> DisplayCallback display state = do clear [ ColorBuffer ] l <- get (leftFirst state) if l then do drawLeftTriangle; drawRightTriangle else do drawRightTriangle; drawLeftTriangle flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho2D 0 1 0 (hf/wf) else ortho2D 0 (wf/hf) 0 1 keyboard :: State -> KeyboardMouseCallback keyboard state (Char c) Down _ _ = case toLower c of 't' -> do leftFirst state $~ not; postRedisplay Nothing '\27' -> exitWith ExitSuccess -- Escape key _ -> return () keyboard _ _ _ _ _ = return () -- Main Loop -- Open window with initial window size, title bar, RGBA display mode, and -- handle input events. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 200 200 _ <- createWindow progName state <- makeState myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard state) displayCallback $= display state mainLoop GLUT-2.7.0.16/examples/RedBook4/AccPersp.hs0000644000000000000000000001401013255126367016177 0ustar0000000000000000{- AccPersp.hs (adapted from accpersp.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE Use the accumulation buffer to do full-scene antialiasing on a scene with perspective projection, using the special routines accFrustum and accPerspective. -} import Data.List ( genericLength ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT -- j8 contains values in the range -.5 < x < .5, -.5 < y < .5, and have a -- gaussian distribution around the origin. Use these to do model jittering for -- scene anti-aliasing and view volume jittering for depth of field effects. Use -- in conjunction with the accwindow routine. j8 :: [Vector2 GLdouble] j8 = [ Vector2 (-0.334818) 0.435331 , Vector2 0.286438 (-0.393495), Vector2 0.459462 0.141540 , Vector2 (-0.414498) (-0.192829), Vector2 (-0.183790) 0.082102 , Vector2 (-0.079263) (-0.317383), Vector2 0.102254 0.299133 , Vector2 0.164216 (-0.054399) ] -- The first 6 arguments are identical to the frustum call. pixD is anti-alias -- jitter in pixels. Use (Vector2 0 0) for no anti-alias jitter. eyeD is -- depth-of field jitter in pixels. Use (Vector2 0 0) for no depth of field -- effects. focus is distance from eye to plane in focus. focus must be greater -- than, but not equal to 0. Note that accFrustum calls translate. You will -- probably want to insure that your ModelView matrix has been initialized to -- identity before calling accFrustum. accFrustum :: GLdouble -> GLdouble -> GLdouble -> GLdouble -> GLdouble -> GLdouble -> Vector2 GLdouble -> Vector2 GLdouble -> GLdouble -> IO () accFrustum left right bottom top zNear zFar (Vector2 pixDx pixDy) (Vector2 eyeDx eyeDy) focus = do (_, Size w h) <- get viewport let xWSize = right - left; yWSize = top - bottom; dx = -(pixDx * xWSize / fromIntegral w + eyeDx * zNear / focus) dy = -(pixDy * yWSize / fromIntegral h + eyeDy * zNear / focus) matrixMode $= Projection loadIdentity frustum (left + dx) (right + dx) (bottom + dy) (top + dy) zNear zFar matrixMode $= Modelview 0 loadIdentity translate (Vector3 (-eyeDx) (-eyeDy) 0) -- The first 4 arguments are identical to the perspective call. pixD is -- anti-alias jitter in pixels. Use (Vector2 0 0) for no anti-alias jitter. eyeD -- is depth-of field jitter in pixels. Use (Vector2 0 0) for no depth of field -- effects. focus is distance from eye to plane in focus. focus must be greater -- than, but not equal to 0. Note that accPerspective calls accFrustum. accPerspective :: GLdouble -> GLdouble -> GLdouble -> GLdouble -> Vector2 GLdouble -> Vector2 GLdouble -> GLdouble -> IO () accPerspective fovY aspect zNear zFar pixD eyeD focus = do let fov2 = ((fovY * pi) / 180) / 2 top = zNear / (cos fov2 / sin fov2) bottom = -top right = top * aspect left = -right accFrustum left right bottom top zNear zFar pixD eyeD focus -- Initialize lighting and other values. myInit :: IO () myInit = do materialAmbient Front $= Color4 1 1 1 1 materialSpecular Front $= Color4 1 1 1 1 materialShininess Front $= 50 position (Light 0) $= Vertex4 0 0 10 1 lightModelAmbient $= Color4 0.2 0.2 0.2 1 lighting $= Enabled light (Light 0) $= Enabled depthFunc $= Just Less shadeModel $= Flat clearColor $= Color4 0 0 0 0 clearAccum $= Color4 0 0 0 0 displayObjects :: IO () displayObjects = do -- resolve overloading, not needed in "real" programs let translatef = translate :: Vector3 GLfloat -> IO () rotatef = rotate :: GLfloat -> Vector3 GLfloat -> IO () preservingMatrix $ do translatef (Vector3 0 0 (-5)) rotatef 30 (Vector3 1 0 0) preservingMatrix $ do translatef (Vector3 (-0.80) 0.35 0) rotatef 100 (Vector3 1 0 0) materialDiffuse Front $= Color4 0.7 0.7 0 1 renderObject Solid (Torus 0.275 0.85 16 16) preservingMatrix $ do translatef (Vector3 (-0.75) (-0.50) 0) rotatef 45 (Vector3 0 0 1) rotatef 45 (Vector3 1 0 0) materialDiffuse Front $= Color4 0 0.7 0.7 1 renderObject Solid (Cube 1.5) preservingMatrix $ do translatef (Vector3 0.75 0.60 0) rotatef 30 (Vector3 1 0 0) materialDiffuse Front $= Color4 0.7 0 0.7 1 renderObject Solid (Sphere' 1 16 16) preservingMatrix $ do translatef (Vector3 0.70 (-0.90) 0.25) materialDiffuse Front $= Color4 0.7 0.4 0.4 1 renderObject Solid Octahedron -- display draws 5 teapots into the accumulation buffer several times; each time -- with a jittered perspective. The focal point is at z = 5.0, so the gold -- teapot will stay in focus. The amount of jitter is adjusted by the magnitude -- of the accPerspective jitter; in this example, 0.33. In this example, the -- teapots are drawn 8 times. display :: DisplayCallback display = do (_, Size w h) <- get viewport clear [ AccumBuffer ] flip mapM_ j8 $ \(Vector2 x y) -> do clear [ ColorBuffer, DepthBuffer ] accPerspective 50 (fromIntegral w / fromIntegral h) 1 15 (Vector2 x y) (Vector2 0 0) 1 displayObjects accum Accum (recip (genericLength j8)) accum Return 1 flush reshape :: ReshapeCallback reshape size = do viewport $= (Position 0 0, size) keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () -- Main Loop: Be certain you request an accumulation buffer. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithAccumBuffer, WithDepthBuffer ] initialWindowSize $= Size 250 250 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit reshapeCallback $= Just reshape displayCallback $= display keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/AccAnti.hs0000644000000000000000000001067313255126367016014 0ustar0000000000000000{- AccAnti.hs (adapted from accanti.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE Use the accumulation buffer to do full-scene antialiasing on a scene with orthographic parallel projection. -} import Data.List ( genericLength ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT -- j8 contains values in the range -.5 < x < .5, -.5 < y < .5, and have a -- gaussian distribution around the origin. Use these to do model jittering for -- scene anti-aliasing and view volume jittering for depth of field effects. Use -- in conjunction with the accwindow routine. j8 :: [Vector2 GLdouble] j8 = [ Vector2 (-0.334818) 0.435331 , Vector2 0.286438 (-0.393495), Vector2 0.459462 0.141540 , Vector2 (-0.414498) (-0.192829), Vector2 (-0.183790) 0.082102 , Vector2 (-0.079263) (-0.317383), Vector2 0.102254 0.299133 , Vector2 0.164216 (-0.054399) ] -- Initialize lighting and other values. myInit :: IO () myInit = do materialAmbient Front $= Color4 1 1 1 1 materialSpecular Front $= Color4 1 1 1 1 materialShininess Front $= 50 position (Light 0) $= Vertex4 0 0 10 1 lightModelAmbient $= Color4 0.2 0.2 0.2 1 lighting $= Enabled light (Light 0) $= Enabled depthFunc $= Just Less shadeModel $= Flat clearColor $= Color4 0 0 0 0 clearAccum $= Color4 0 0 0 0 displayObjects :: IO () displayObjects = do -- resolve overloading, not needed in "real" programs let translatef = translate :: Vector3 GLfloat -> IO () rotatef = rotate :: GLfloat -> Vector3 GLfloat -> IO () preservingMatrix $ do rotatef 30 (Vector3 1 0 0) preservingMatrix $ do translatef (Vector3 (-0.80) 0.35 0) rotatef 100 (Vector3 1 0 0) materialDiffuse Front $= Color4 0.7 0.7 0 1 renderObject Solid (Torus 0.275 0.85 16 16) preservingMatrix $ do translatef (Vector3 (-0.75) (-0.50) 0) rotatef 45 (Vector3 0 0 1) rotatef 45 (Vector3 1 0 0) materialDiffuse Front $= Color4 0 0.7 0.7 1 renderObject Solid (Cube 1.5) preservingMatrix $ do translatef (Vector3 0.75 0.60 0) rotatef 30 (Vector3 1 0 0) materialDiffuse Front $= Color4 0.7 0 0.7 1 renderObject Solid (Sphere' 1 16 16) preservingMatrix $ do translatef (Vector3 0.70 (-0.90) 0.25) materialDiffuse Front $= Color4 0.7 0.4 0.4 1 renderObject Solid Octahedron -- display draws 5 teapots into the accumulation buffer several times; each time -- with a jittered perspective. The focal point is at z = 5.0, so the gold -- teapot will stay in focus. The amount of jitter is adjusted by the magnitude -- of the accPerspective jitter; in this example, 0.33. In this example, the -- teapots are drawn 8 times. display :: DisplayCallback display = do (_, Size w h) <- get viewport clear [ AccumBuffer ] flip mapM_ j8 $ \(Vector2 x y) -> do clear [ ColorBuffer, DepthBuffer ] preservingMatrix $ do -- Note that 4.5 is the distance in world space between left and right -- and bottom and top. This formula converts fractional pixel movement -- to world coordinates. translate (Vector3 (x*4.5/fromIntegral w) (y*4.5/fromIntegral h) 0) displayObjects accum Accum (recip (genericLength j8)) accum Return 1 flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho (-2.25) 2.25 (-2.25*hf/wf) (2.25*hf/wf) (-10) 10 else ortho (-2.25*wf/hf) (2.25*wf/hf) (-2.25) 2.25 (-10) 10 matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () -- Main Loop: Be certain to request an accumulation buffer. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode, WithAccumBuffer, WithDepthBuffer ] initialWindowSize $= Size 250 250 initialWindowPosition $= Position 100 100 _ <- createWindow progName myInit reshapeCallback $= Just reshape displayCallback $= display keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/RedBook4/AARGB.hs0000644000000000000000000000606013255126367015321 0ustar0000000000000000{- AARGB.hs (adapted from aargb.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program draws shows how to draw anti-aliased lines. It draws two diagonal lines to form an X; when 'r' is typed in the window, the lines are rotated in opposite directions. -} import Data.Char ( toLower ) import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { rotAngle :: IORef Int } makeState :: IO State makeState = do r <- newIORef 0 return $ State { rotAngle = r } -- Initialize antialiasing for RGBA mode, including alpha blending, hint, and -- line width. Print out implementation specific info on line width granularity -- and width. myInit :: IO () myInit = do g <- get smoothLineWidthGranularity putStrLn ("smoothLineWidthGranularity is " ++ show g) r <- get smoothLineWidthRange putStrLn ("smoothLineWidthRange is " ++ show r) lineSmooth $= Enabled blend $= Enabled blendFunc $= (SrcAlpha, OneMinusSrcAlpha) hint LineSmooth $= DontCare lineWidth $= 1.5 clearColor $= Color4 0 0 0 0 -- Draw 2 diagonal lines to form an X display :: State -> DisplayCallback display state = do r <- get (rotAngle state) clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () vertex2f = vertex :: Vertex2 GLfloat -> IO () color3f (Color3 0 1 0) preservingMatrix $ do rotate (-(fromIntegral r :: GLfloat)) (Vector3 0 0 0.1) renderPrimitive Lines $ do vertex2f (Vertex2 (-0.5) 0.5) vertex2f (Vertex2 0.5 (-0.5)) color3f (Color3 0 0 1) preservingMatrix $ do rotate (fromIntegral r :: GLfloat) (Vector3 0 0 0.1) renderPrimitive Lines $ do vertex2f (Vertex2 0.5 0.5) vertex2f (Vertex2 (-0.5) (-0.5)) flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho2D (-1) 1 (-1*hf/wf) (1*hf/wf) else ortho2D (-1*wf/hf) (1*wf/hf) (-1) 1 matrixMode $= Modelview 0 loadIdentity keyboard :: State -> KeyboardMouseCallback keyboard state (Char c) Down _ _ = case toLower c of 'r' -> do rotAngle state $~ ((`mod` 360) . (+ 30)); postRedisplay Nothing '\27' -> exitWith ExitSuccess _ -> return () keyboard _ _ _ _ _ = return () -- Main Loop -- Open window with initial window size, title bar, -- RGBA display mode, and handle input events. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 200 200 _ <- createWindow progName state <- makeState myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard state) displayCallback $= display state mainLoop GLUT-2.7.0.16/examples/RedBook4/AAIndex.hs0000644000000000000000000000623713255126367015764 0ustar0000000000000000{- AAIndex.hs (adapted from aaindex.c which is (c) Silicon Graphics, Inc.) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program draws shows how to draw anti-aliased lines in color index mode. It draws two diagonal lines to form an X; when 'r' is typed in the window, the lines are rotated in opposite directions. -} import Data.Char ( toLower ) import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT data State = State { rotAngle :: IORef Int } makeState :: IO State makeState = do r <- newIORef 0 return $ State { rotAngle = r } rampSize, ramp1Start, ramp2Start :: GLint rampSize = 16 ramp1Start = 32 ramp2Start = 48 -- Initialize antialiasing for color index mode, including loading a green color -- ramp starting at ramp1Start, and a blue color ramp starting at ramp2Start. -- The ramps must be a multiple of 16. myInit :: IO () myInit = do flip mapM_ [ 0 .. rampSize - 1 ] $ \i -> do let shade = fromIntegral i / fromIntegral rampSize colorMapEntry (Index1 (ramp1Start + i)) $= Color3 0 shade 0 colorMapEntry (Index1 (ramp2Start + i)) $= Color3 0 0 shade lineSmooth $= Enabled hint LineSmooth $= DontCare lineWidth $= 1.5 clearIndex $= Index1 (fromIntegral ramp1Start) -- Draw 2 diagonal lines to form an X display :: State -> DisplayCallback display state = do r <- get (rotAngle state) clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let vertex2f = vertex :: Vertex2 GLfloat -> IO () index (Index1 ramp1Start) preservingMatrix $ do rotate (-(fromIntegral r :: GLfloat)) (Vector3 0 0 0.1) renderPrimitive Lines $ do vertex2f (Vertex2 (-0.5) 0.5) vertex2f (Vertex2 0.5 (-0.5)) index (Index1 ramp2Start) preservingMatrix $ do rotate (fromIntegral r :: GLfloat) (Vector3 0 0 0.1) renderPrimitive Lines $ do vertex2f (Vertex2 0.5 0.5) vertex2f (Vertex2 (-0.5) (-0.5)) flush reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity let wf = fromIntegral w hf = fromIntegral h if w <= h then ortho2D (-1) 1 (-1*hf/wf) (1*hf/wf) else ortho2D (-1*wf/hf) (1*wf/hf) (-1) 1 matrixMode $= Modelview 0 loadIdentity keyboard :: State -> KeyboardMouseCallback keyboard state (Char c) Down _ _ = case toLower c of 'r' -> do rotAngle state $~ ((`mod` 360) . (+ 30)); postRedisplay Nothing '\27' -> exitWith ExitSuccess _ -> return () keyboard _ _ _ _ _ = return () -- Main Loop -- Open window with initial window size, title bar, -- color index display mode, and handle input events. main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, IndexMode ] initialWindowSize $= Size 200 200 _ <- createWindow progName state <- makeState myInit reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard state) displayCallback $= display state mainLoop GLUT-2.7.0.16/examples/OrangeBook/ogl2brick/Brick.hs0000644000000000000000000002560113255126367020034 0ustar0000000000000000{-# LANGUAGE CPP #-} {- Brick.hs (adapted from ogl2brick.c which is (c) 3Dlabs Inc. Ltd.) Copyright (c) Sven Panne 2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE -} #if !MIN_VERSION_base(4,8,0) import Prelude hiding ( sum ) import Data.Foldable ( Foldable, sum ) #endif import Control.Applicative import Control.Exception ( IOException, catch ) import Control.Monad ( when, unless ) import qualified Data.ByteString as B import Data.IORef import System.Exit import Graphics.UI.GLUT infixl 6 $+, $- infixl 7 $* inertiaThreshold, inertiaFactor :: GLfloat inertiaThreshold = 1 inertiaFactor = 0.5 scaleFactor, scaleIncrement :: GLfloat scaleFactor = 0.01 scaleIncrement = 0.5 timerFrequencyMillis :: Timeout timerFrequencyMillis = 20 clearColors :: [Color4 GLclampf] clearColors = [ Color4 0.0 0.0 0.0 1, Color4 0.2 0.2 0.3 1, Color4 0.7 0.7 0.7 1 ] models :: [IO ()] models = [ drawCube, renderObject Solid (Teapot 0.6), renderObject Solid (Sphere' 0.6 64 64), renderObject Solid (Torus 0.2 0.6 64 64) ] initialDiff :: Vector3 GLfloat initialDiff = Vector3 206 16 10 initialInertia :: Vector3 GLfloat initialInertia = Vector3 (-0.5) 0 0 data State = State { diff :: IORef (Vector3 GLfloat), lastIncr :: IORef (Vector3 GLfloat), inertia :: IORef (Vector3 GLfloat), inertiaOld :: IORef (Vector3 GLfloat), theScale :: IORef GLfloat, lastPosition :: IORef Position, shouldRotate :: IORef Bool, colorCycle :: IORef [Color4 GLclampf], modelCycle :: IORef [IO ()], modifiers :: IORef Modifiers } makeState :: IO State makeState = do di <- newIORef initialDiff li <- newIORef (pure 0) ia <- newIORef initialInertia io <- newIORef (pure 0) sc <- newIORef 1 lp <- newIORef (Position (-1) (-1)) sr <- newIORef True cc <- newIORef (cycle clearColors) mc <- newIORef (cycle models) mo <- newIORef (Modifiers Up Up Up) return $ State { diff = di, lastIncr = li, inertia = ia, inertiaOld = io, theScale = sc, lastPosition = lp, shouldRotate = sr, colorCycle = cc, modelCycle = mc, modifiers = mo } -- Our tiny vector math library... ($+), ($-), ($*) :: (Applicative t, Num a) => t a -> t a -> t a ($+) = liftA2 (+) ($-) = liftA2 (-) ($*) = liftA2 (*) step :: (Applicative t, Num a, Ord a) => t a -> t a -> t a step = liftA2 (\e x -> if x < e then 0 else 1) dot :: (Applicative t, Foldable t, Num a) => t a -> t a -> a dot v1 v2 = sum (v1 $* v2) drawFace :: Normal3 GLfloat -> Vertex3 GLfloat -> Vertex3 GLfloat -> Vertex3 GLfloat -> Vertex3 GLfloat -> IO () drawFace p q r s t = do let texCoord2f = texCoord :: TexCoord2 GLfloat -> IO () normal p texCoord2f (TexCoord2 1 1) vertex q texCoord2f (TexCoord2 0 1) vertex r texCoord2f (TexCoord2 0 0) vertex s texCoord2f (TexCoord2 1 0) vertex t drawCube :: IO () drawCube = do let size = 1 sc = 0.2 delta = 0.1 a = Vertex3 size size ( size * sc + delta) b = Vertex3 size size (-size * sc + delta) c = Vertex3 size (-size) (-size * sc) d = Vertex3 size (-size) ( size * sc) e = Vertex3 (-size) size ( size * sc + delta) f = Vertex3 (-size) size (-size * sc + delta) g = Vertex3 (-size) (-size) (-size * sc) h = Vertex3 (-size) (-size) ( size * sc) i = Normal3 1 0 0 k = Normal3 (-1) 0 0 l = Normal3 0 0 (-1) m = Normal3 0 0 1 n = Normal3 0 1 0 o = Normal3 0 (-1) 0 renderPrimitive Quads $ do drawFace i d c b a drawFace k g h e f drawFace l c g f b drawFace m h d a e drawFace n e a b f drawFace o g c d h display :: State -> DisplayCallback display state = do loadIdentity translate (Vector3 0 0 (-5 :: GLfloat)) Vector3 xDiff yDiff zDiff <- get (diff state) rotate yDiff (Vector3 1 0 0) rotate xDiff (Vector3 0 1 0) rotate zDiff (Vector3 0 0 1) sc <- get (theScale state) scale sc sc sc clear [ ColorBuffer, DepthBuffer ] (drawModel:_) <- get (modelCycle state) drawModel flush swapBuffers nextClearColor :: State -> IO () nextClearColor state = do cc <- get (colorCycle state) clearColor $= head cc colorCycle state $~ tail toggleRotation :: State -> IO () toggleRotation state = do rot <- get (shouldRotate state) shouldRotate state $~ not if rot then do ia <- get (inertia state) inertiaOld state $= ia else do io <- get (inertiaOld state) inertia state $= io -- To prevent confusion, force some rotation when (dot io io == 0) $ inertia state $= initialInertia printHelp :: IO () printHelp = mapM_ putStrLn [ "", "Keyboard commands:", "", "b - Toggle among background clear colors", "q, - Quit", "t - Toggle among models to render", "? - Help", " - reset zoom and rotation", " or - stop rotation", "<+>, <-> or - zoom model", " or - rotate model", ""] resetState :: State -> IO () resetState state = do diff state $= initialDiff lastIncr state $= pure 0 inertia state $= initialInertia theScale state $= 1 calcInertia :: State -> IO () calcInertia state = do lastPosition state $= Position (-1) (-1) li <- get (lastIncr state) ia <- get (inertia state) let t = pure inertiaThreshold f = pure inertiaFactor l = (pure 1 $- (step (fmap negate t) li)) $* ((li $+ t) $* f $- ia) r = (step t li) $* ((li $- t) $* f $- ia) inertia state $= l $+ ia $+ r lastIncr state $= pure 0 keyboard :: State -> KeyboardMouseCallback keyboard state key keyState mods _ = do modifiers state $= mods postRedisplay Nothing case (key, keyState) of (Char 'b', Down) -> nextClearColor state (Char 'q', Down) -> exitWith ExitSuccess (Char '\27', Down) -> exitWith ExitSuccess (Char 't', Down) -> modelCycle state $~ tail (Char ' ', Down) -> toggleRotation state (Char '+', Down) -> theScale state $~ (+ scaleIncrement) (Char '-', Down) -> theScale state $~ (+ (- scaleIncrement)) (Char _, Down) -> printHelp (SpecialKey KeyHome, Down) -> resetState state (SpecialKey KeyLeft, Down) -> diff state $~ ($- Vector3 1 0 0) (SpecialKey KeyRight, Down) -> diff state $~ ($+ Vector3 1 0 0) (SpecialKey KeyUp, Down) -> diff state $~ ($- Vector3 0 1 0) (SpecialKey KeyDown, Down) -> diff state $~ ($+ Vector3 0 1 0) (MouseButton LeftButton, Down) -> do inertia state $= pure 0 lastIncr state $= pure 0 (MouseButton LeftButton, Up) -> calcInertia state (_, _) -> return () motion :: State -> MotionCallback motion state pos@(Position x y) = do postRedisplay Nothing Position xt yt <- get (lastPosition state) lastPosition state $= pos when (xt /= -1 || yt /= -1) $ do let li@(Vector3 xl yl _) = Vector3 (fromIntegral (x - xt)) (fromIntegral (y - yt)) 0 lastIncr state $= li when (xt /= -1) $ do mods <- get (modifiers state) if ctrl mods == Down then do diff state $~ ($+ Vector3 0 0 xl) theScale state $~ (+ (yl * scaleFactor)) else diff state $~ ($+ li) timer :: State -> TimerCallback timer state = do rot <- get (shouldRotate state) when rot $ do ia <- get (inertia state) diff state $~ ($+ ia) postRedisplay Nothing addTimerCallback timerFrequencyMillis (timer state) reshape :: ReshapeCallback reshape size@(Size w h) = do let vp = 0.8 aspect = fromIntegral w / fromIntegral h viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity frustum (-vp) vp (-vp / aspect) (vp / aspect) 3 10 matrixMode $= Modelview 0 loadIdentity translate (Vector3 0 0 (-5 :: GLfloat)) -- Make sure that GLSL is supported by the driver, either directly by the core -- or via an extension. checkGLSLSupport :: IO () checkGLSLSupport = do version <- get (majorMinor glVersion) unless (version >= (2,0)) $ do extensions <- get glExtensions unless ("GL_ARB_shading_language_100" `elem` extensions) $ ioError (userError "No GLSL support found.") readAndCompileShader :: ShaderType -> FilePath -> IO Shader readAndCompileShader st filePath = do src <- B.readFile filePath shader <- createShader st shaderSourceBS shader $= src compileShader shader reportErrors ok <- get (compileStatus shader) infoLog <- get (shaderInfoLog shader) mapM_ putStrLn ["Shader info log for '" ++ filePath ++ "':", infoLog, ""] unless ok $ do deleteObjectNames [shader] ioError (userError "shader compilation failed") return shader installBrickShaders :: [Shader] -> IO () installBrickShaders shaders = do brickProg <- createProgram attachedShaders brickProg $= shaders linkProgram brickProg reportErrors ok <- get (linkStatus brickProg) infoLog <- get (programInfoLog brickProg) mapM_ putStrLn ["Program info log:", infoLog, ""] unless ok $ do deleteObjectNames [brickProg] ioError (userError "linking failed") currentProgram $= Just brickProg let setUniform var val = do location <- get (uniformLocation brickProg var) reportErrors uniform location $= val setUniform "BrickColor" (Color3 1.0 0.3 (0.2 :: GLfloat)) setUniform "MortarColor" (Color3 0.85 0.86 (0.84 :: GLfloat)) setUniform "BrickSize" (Vertex2 0.30 (0.15 :: GLfloat)) setUniform "BrickPct" (Vertex2 0.90 (0.85 :: GLfloat)) setUniform "LightPosition" (Vertex3 0 0 (4 :: GLfloat)) main :: IO () main = do _ <- getArgsAndInitialize initialDisplayMode $= [ RGBMode, WithDepthBuffer, DoubleBuffered ] initialWindowSize $= Size 500 500 _ <- createWindow "3Dlabs Brick Shader" -- Note: We don't use an idle callback, we redisplay more intelligently. state <- makeState displayCallback $= display state keyboardMouseCallback $= Just (keyboard state) reshapeCallback $= Just reshape motionCallback $= Just (motion state) addTimerCallback timerFrequencyMillis (timer state) Control.Exception.catch (do checkGLSLSupport vs <- readAndCompileShader VertexShader "Brick.vert" fs <- readAndCompileShader FragmentShader "Brick.frag" installBrickShaders [vs, fs]) (\exception -> do print (exception :: IOException) putStrLn "Using fixed function pipeline." materialDiffuse Front $= Color4 1 0.3 0.2 1 materialSpecular Front $= Color4 0.3 0.3 0.3 1 materialShininess Front $= 16 position (Light 0) $= Vertex4 0 0 4 0 lighting $= Enabled light (Light 0) $= Enabled) depthFunc $= Just Less nextClearColor state -- display help keyboard state (Char '?') Down (Modifiers Up Up Up) (Position 0 0) mainLoop GLUT-2.7.0.16/examples/Misc/Triangulate.hs0000644000000000000000000000767313255126367016261 0ustar0000000000000000{- Triangulate.hs (adapted from tess.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates polygon triangulation. Two tesselated objects are drawn. The first is a rectangle with a triangular hole. The second is a smooth shaded, self-intersecting star. Note the exterior rectangle is drawn with its vertices in counter-clockwise order, but its interior clockwise. Note the combineCallback is needed for the self-intersecting star. Also note that removing the TessProperty for the star will make the interior unshaded (TessWindingOdd). -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import System.Random ( randomIO ) import Graphics.UI.GLUT display :: [DisplayList] -> DisplayCallback display displayLists = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () color3f (Color3 1 1 1) mapM_ callList displayLists flush -- 'Float' is a dummy, any marshalable type would do type DontCare = Float rectangle :: ComplexContour DontCare rectangle = ComplexContour [ AnnotatedVertex (Vertex3 50 50 0) 0, AnnotatedVertex (Vertex3 200 50 0) 0, AnnotatedVertex (Vertex3 200 200 0) 0, AnnotatedVertex (Vertex3 50 200 0) 0 ] tri :: ComplexContour DontCare tri = ComplexContour [ AnnotatedVertex (Vertex3 75 75 0) 0, AnnotatedVertex (Vertex3 125 175 0) 0, AnnotatedVertex (Vertex3 175 75 0) 0 ] rectAndTri :: ComplexPolygon DontCare rectAndTri = ComplexPolygon [ rectangle, tri ] star :: ComplexPolygon DontCare star = ComplexPolygon [ ComplexContour [ AnnotatedVertex (Vertex3 250 50 0) 0, AnnotatedVertex (Vertex3 325 200 0) 0, AnnotatedVertex (Vertex3 400 50 0) 0, AnnotatedVertex (Vertex3 250 150 0) 0, AnnotatedVertex (Vertex3 400 150 0) 0 ] ] myInit :: IO [DisplayList] myInit = do clearColor $= Color4 0 0 0 0 rectAndTriList <- compileNewList TessWindingOdd rectAndTri starList <- compileNewList TessWindingPositive star return [ rectAndTriList, starList ] compileNewList :: TessWinding -> ComplexPolygon DontCare -> IO DisplayList compileNewList windingRule complexPolygon = defineNewList Compile $ drawTriangulation =<< triangulate windingRule 0 (Normal3 0 0 0) noOpCombiner complexPolygon noOpCombiner :: Combiner DontCare noOpCombiner _newVertex _weightedProperties = 0 drawTriangulation :: Triangulation DontCare -> IO () drawTriangulation (Triangulation triangles) = renderPrimitive Triangles $ flip mapM_ triangles $ \(Triangle tv1 tv2 tv3) -> do randomColor drawTriangleVertex tv1 drawTriangleVertex tv2 drawTriangleVertex tv3 -- CFloat has no Random instance, so we go via Float randomGLfloat :: IO GLfloat randomGLfloat = fmap (realToFrac :: Float -> GLfloat) randomIO randomColor :: IO () randomColor = do r <- randomGLfloat g <- randomGLfloat b <- randomGLfloat color (Color3 r g b) drawTriangleVertex :: TriangleVertex DontCare -> IO () drawTriangleVertex (AnnotatedVertex plainVertex (_, e)) = do edgeFlag $= e vertex plainVertex reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho2D 0 (fromIntegral w) 0 (fromIntegral h) matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 500 500 _ <- createWindow progName displayLists <- myInit displayCallback $= display displayLists reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/Misc/SmoothOpenGL3.hs0000644000000000000000000002103013255126367016362 0ustar0000000000000000{-# LANGUAGE CPP #-} {- SmoothOpenGL3.hs (adapted from freeglut's smooth_opengl3.c example) Copyright (c) Sven Panne 2018 This file is part of HOpenGL and distributed under a BSD-style license See the file LICENSE -} import Control.Monad import qualified Data.ByteString as B import Data.List import Foreign.Marshal.Array import Foreign.Ptr import Foreign.Storable #if MIN_VERSION_OpenGLRaw(3,0,0) import Graphics.GL #else import Graphics.Rendering.OpenGL.Raw #define GL_FALSE gl_FALSE #define GL_TRUE gl_TRUE #endif import Graphics.UI.GLUT import System.Exit import System.IO data State = State { vertexBufferName :: BufferObject, vertexArrayObject :: VertexArrayObject, fgProjectionMatrixIndex :: UniformLocation, fgColorIndex :: AttribLocation , fgVertexIndex :: AttribLocation, projectionMatrix :: GLmatrix GLfloat } checkError :: String -> IO () checkError functionName = get errors >>= mapM_ reportError where reportError e = hPutStrLn stderr (showError e ++ " detected in " ++ functionName) showError (Error category message) = "GL error " ++ show category ++ " (" ++ message ++ ")" varray :: [GLfloat] varray = [ 1, 0, 0, -- red 5, 5, -- lower left 0, 1, 0, -- green 25, 5, -- lower right 0, 0, 1, -- blue 5, 25 ] -- upper left numColorComponents :: NumComponents numColorComponents = 3 numVertexComponents :: NumComponents numVertexComponents = 2 sizeOfComponent :: Int sizeOfComponent = sizeOf (head varray) stride :: Stride stride = fromIntegral sizeOfComponent * fromIntegral (numColorComponents + numVertexComponents) sizeOfVarray :: Int sizeOfVarray = length varray * sizeOfComponent numElements :: NumArrayIndices numElements = fromIntegral sizeOfVarray `div` fromIntegral stride initBuffer :: IO BufferObject initBuffer = do bufferObject <- genObjectName bindBuffer ArrayBuffer $= Just bufferObject withArray varray $ \buffer -> bufferData ArrayBuffer $= (fromIntegral sizeOfVarray, buffer, StaticDraw) checkError "initBuffer" return bufferObject vertexShaderSource :: B.ByteString vertexShaderSource = packUtf8 . unlines $ [ "#version 140", "uniform mat4 fg_ProjectionMatrix;", "in vec4 fg_Color;", "in vec4 fg_Vertex;", "smooth out vec4 fg_SmoothColor;", "void main()", "{", " fg_SmoothColor = fg_Color;", " gl_Position = fg_ProjectionMatrix * fg_Vertex;", "}" ] fragmentShaderSource :: B.ByteString fragmentShaderSource = packUtf8 . unlines $ [ "#version 140", "smooth in vec4 fg_SmoothColor;", "out vec4 fg_FragColor;", "void main(void)", "{", " fg_FragColor = fg_SmoothColor;", "}" ] checked :: (t -> IO ()) -> (t -> GettableStateVar Bool) -> (t -> GettableStateVar String) -> String -> t -> IO () checked action getStatus getInfoLog message object = do action object status <- get (getStatus object) unless status $ hPutStrLn stderr . ((message ++ " log: ") ++) =<< get (getInfoLog object) compileAndCheck :: Shader -> IO () compileAndCheck = checked compileShader compileStatus shaderInfoLog "compile" compileShaderSource :: ShaderType -> B.ByteString -> IO Shader compileShaderSource st source = do shader <- createShader st shaderSourceBS shader $= source compileAndCheck shader return shader linkAndCheck :: Program -> IO () linkAndCheck = checked linkProgram linkStatus programInfoLog "link" createProgramUsing :: [Shader] -> IO Program createProgramUsing shaders = do program <- createProgram attachedShaders program $= shaders linkAndCheck program return program initShader :: IO (UniformLocation, AttribLocation, AttribLocation) initShader = do vertexShader <- compileShaderSource VertexShader vertexShaderSource fragmentShader <- compileShaderSource FragmentShader fragmentShaderSource program <- createProgramUsing [vertexShader, fragmentShader] currentProgram $= Just program projectionMatrixIndex <- get (uniformLocation program "fg_ProjectionMatrix") colorIndex <- get (attribLocation program "fg_Color") vertexAttribArray colorIndex $= Enabled vertexIndex <- get (attribLocation program "fg_Vertex") vertexAttribArray vertexIndex $= Enabled checkError "initShader" return (projectionMatrixIndex, colorIndex, vertexIndex) initRendering :: IO () initRendering = do clearColor $= Color4 0 0 0 0 checkError "initRendering" myInit :: IO State myInit = do vao <- genObjectName bindVertexArrayObject $= Just vao bufferObject <- initBuffer (projectionMatrixIndex, colorIndex, vertexIndex) <- initShader initRendering m <- newMatrix ColumnMajor (replicate 16 0) return $ State { vertexBufferName = bufferObject, vertexArrayObject = vao, fgProjectionMatrixIndex = projectionMatrixIndex, fgColorIndex = colorIndex, fgVertexIndex = vertexIndex, projectionMatrix = m } dumpInfo :: IO () dumpInfo = do let dump :: String -> GettableStateVar String -> IO () dump message var = putStrLn . ((message ++ ": ") ++) =<< get var dump "Vendor" vendor dump "Renderer" renderer dump "Version" glVersion dump "GLSL" shadingLanguageVersion checkError "dumpInfo" bufferObjectPtr :: Integral a => a -> Ptr b bufferObjectPtr = plusPtr (nullPtr :: Ptr GLchar) . fromIntegral vertexArrayDescriptor :: NumComponents -> NumComponents -> VertexArrayDescriptor a vertexArrayDescriptor count offset = VertexArrayDescriptor count Float stride (bufferObjectPtr (fromIntegral sizeOfComponent * offset)) triangle :: State -> IO () triangle state = do withMatrix (projectionMatrix state) $ \order buffer -> uniformMatrix4fv (fgProjectionMatrixIndex state) 1 (order == RowMajor) buffer bindVertexArrayObject $= Just (vertexArrayObject state) bindBuffer ArrayBuffer $= Just (vertexBufferName state) vertexAttribPointer (fgColorIndex state) $= (ToFloat, vertexArrayDescriptor numColorComponents 0) vertexAttribPointer (fgVertexIndex state) $= (ToFloat, vertexArrayDescriptor numVertexComponents numColorComponents) drawArrays Triangles 0 numElements checkError "triangle" -- The OpenGL package offers no interface for glUniformMatrix*fv yet uniformMatrix4fv :: UniformLocation -> GLsizei -> Bool -> Ptr GLfloat -> IO () uniformMatrix4fv location count = glUniformMatrix4fv (uniformLocationToGLint location) count . marshalGLboolean where marshalGLboolean x = fromIntegral $ case x of False -> GL_FALSE True -> GL_TRUE -- MEGA HACK because UniformLocation is abstract uniformLocationToGLint = read . head . tail . words . show display :: State -> DisplayCallback display state = do clear [ ColorBuffer ] triangle state flush checkError "display" loadOrtho :: (Matrix m, MatrixComponent a, Fractional a) => m a -> a -> a -> a -> a -> a -> a -> IO () loadOrtho m l r b t n f = fillMatrix m [ [2 / (r - l), 0, 0, 0], [0, 2 / (t - b), 0, 0], [0, 0, -2 / (f - n), 0], [-(r + l) / (r - l), -(t + b) / (t - b), -(f + n) / (f - n), 1 ]] fillMatrix :: (Matrix m, MatrixComponent a) => m a -> [[a]] -> IO () fillMatrix m xs = withMatrix m $ \order buffer -> pokeArray buffer . concat . rearrange order $ xs rearrange :: MatrixOrder -> [[a]] -> [[a]] rearrange ColumnMajor = id rearrange RowMajor = transpose loadOrtho2D :: (Matrix m, MatrixComponent a, Fractional a) => m a -> a -> a -> a -> a -> IO () loadOrtho2D m l r b t = loadOrtho m l r b t (-1) 1 reshape :: State -> ReshapeCallback reshape state size@(Size w h) = do viewport $= (Position 0 0, size) let wf = fromIntegral w hf = fromIntegral h if w <= h then loadOrtho2D (projectionMatrix state) 0 30 0 (30 * hf / wf) else loadOrtho2D (projectionMatrix state) 0 (30 * wf / hf) 0 30 checkError "reshape" keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] -- add command line argument "classic" for a pre-3.x context unless (args == ["classic"]) $ do initialContextVersion $= (3, 1) initialContextFlags $= [ ForwardCompatibleContext, DebugContext ] initialWindowSize $= Size 500 500 initialWindowPosition $= Position 100 100 _ <- createWindow progName dumpInfo state <- myInit displayCallback $= display state reshapeCallback $= Just (reshape state) keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/Misc/Pitfall14.hs0000644000000000000000000000213213255126367015523 0ustar0000000000000000{- Pitfall14 Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates pitfall 14 (Careful Enabling Color Material) of Mark Kilgard's "16 Common OpenGL Pitfalls", see: http://www.opengl.org/resources/features/KilgardTechniques/oglpitfall/ -} import Control.Monad ( unless ) import System.Exit ( exitFailure ) import Graphics.UI.GLUT main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] _ <- createWindow progName currentColor $= Color4 1 1 1 1 materialAmbient Front $= Color4 0.1 0.1 0.1 1 -- re-get to avoid any rounding issues mafBefore <- get (materialAmbient Front) colorMaterial $= Just (Front, Diffuse) mafAfter <- get (materialAmbient Front) unless (mafBefore == mafAfter) $ do putStrLn "ERROR: The ambient material property changed!" putStrLn (" before: " ++ show mafBefore) putStrLn (" after : " ++ show mafAfter) exitFailure GLUT-2.7.0.16/examples/Misc/Gears.hs0000644000000000000000000002455212604702100015014 0ustar0000000000000000{- Gears.hs (adapted from gears.c which is (c) Brian Paul) Copyright (c) Shawn P. Garbett 2004 Further hacked by Sven Panne This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE Command line options: -info print GL implementation information -exit automatically exit after 30 seconds -} -------------------------------------------------------------------------------- import Control.Monad ( when ) import Data.IORef ( IORef, newIORef ) import Data.List ( intersperse ) import System.Console.GetOpt import System.Exit ( exitWith, ExitCode(ExitSuccess), exitFailure ) import Graphics.UI.GLUT -------------------------------------------------------------------------------- type View = (GLfloat, GLfloat, GLfloat) data State = State { frames :: IORef Int, t0 :: IORef Int, viewRot :: IORef View, angle' :: IORef GLfloat } makeState :: IO State makeState = do f <- newIORef 0 t <- newIORef 0 v <- newIORef (20, 30, 0) a <- newIORef 0 return $ State { frames = f, t0 = t, viewRot = v, angle' = a } -- Draw a gear wheel. You'll probably want to call this function when -- building a display list since we do a lot of trig here. -- -- Input: innerRadius - radius of hole at center -- outerRadius - radius at center of teeth -- width - width of gear -- teeth - number of teeth -- toothDepth - depth of tooth gear :: GLfloat -> GLfloat -> GLfloat -> GLint -> GLfloat -> IO () gear innerRadius outerRadius width teeth toothDepth = do let r0 = innerRadius r1 = outerRadius - toothDepth / 2 r2 = outerRadius + toothDepth / 2 da = 2 * pi / fromIntegral teeth / 4 w = 0.5 * width render p f = renderPrimitive p $ mapM_ (\i -> let angle = fromIntegral i * 2 * pi / fromIntegral teeth in f r0 r1 r2 w da teeth i angle) [ 0 .. teeth ] shadeModel $= Flat currentNormal $= Normal3 0 0 1 render QuadStrip gearFront render Quads teethFront currentNormal $= Normal3 0 0 (-1) render QuadStrip gearBack render Quads teethBack render QuadStrip teethFace shadeModel $= Smooth render QuadStrip gearInside type Renderer = GLfloat -> GLfloat -> GLfloat -> GLfloat -> GLfloat -> GLint -> GLint -> GLfloat -> IO () -- draw front face gearFront :: Renderer gearFront r0 r1 _ w da teeth i angle = do vertex (Vertex3 (r0 * cos angle) (r0 * sin angle) w) vertex (Vertex3 (r1 * cos angle) (r1 * sin angle) w) when (i < teeth) $ do vertex (Vertex3 (r0 * cos angle ) (r0 * sin angle ) w) vertex (Vertex3 (r1 * cos (angle + 3 * da)) (r1 * sin (angle + 3 * da)) w) -- draw front sides of teeth teethFront :: Renderer teethFront _ r1 r2 w da teeth i angle = when (i < teeth) $ do vertex (Vertex3 (r1 * cos angle ) (r1 * sin angle ) w) vertex (Vertex3 (r2 * cos (angle + da)) (r2 * sin (angle + da)) w) vertex (Vertex3 (r2 * cos (angle + 2 * da)) (r2 * sin (angle + 2 * da)) w) vertex (Vertex3 (r1 * cos (angle + 3 * da)) (r1 * sin (angle + 3 * da)) w) -- draw back face gearBack :: Renderer gearBack r0 r1 _ w da teeth i angle = do vertex (Vertex3 (r1 * cos angle) (r1 * sin angle) (-w)) vertex (Vertex3 (r0 * cos angle) (r0 * sin angle) (-w)) when (i < teeth) $ do vertex (Vertex3 (r1 * cos (angle + 3 * da)) (r1 * sin (angle + 3 * da)) (-w)) vertex (Vertex3 (r0 * cos angle ) (r0 * sin angle ) (-w)) -- draw back sides of teeth teethBack :: Renderer teethBack _ r1 r2 w da teeth i angle = when (i < teeth) $ do vertex (Vertex3 (r1 * cos (angle + 3 * da)) (r1 * sin (angle + 3 * da)) (-w)) vertex (Vertex3 (r2 * cos (angle + 2 * da)) (r2 * sin (angle + 2 * da)) (-w)) vertex (Vertex3 (r2 * cos (angle + da)) (r2 * sin (angle + da)) (-w)) vertex (Vertex3 (r1 * cos angle ) (r1 * sin angle ) (-w)) -- draw outward faces of teeth teethFace :: Renderer teethFace _ r1 r2 w da teeth i angle = if (i < teeth) then do vertex (Vertex3 (r1*(cos angle)) (r1*(sin angle)) w) vertex (Vertex3 (r1*(cos angle)) (r1*(sin angle)) (-w)) let u' = r2 * cos (angle + da) - r1 * cos angle v' = r2 * sin (angle + da) - r1 * sin angle len = sqrt (u' * u' + v' * v') u = u' / len v = v' / len currentNormal $= Normal3 v (-u) 0 vertex (Vertex3 (r2 * cos (angle + da)) (r2 * sin (angle + da)) w ) vertex (Vertex3 (r2 * cos (angle + da)) (r2 * sin (angle + da)) (-w)) currentNormal $= Normal3 (cos angle) (sin angle) 0 vertex (Vertex3 (r2 * cos (angle + 2 * da)) (r2 * sin (angle + 2 * da)) w ) vertex (Vertex3 (r2 * cos (angle + 2 * da)) (r2 * sin (angle + 2 * da)) (-w)) let u2 = r1 * cos (angle + 3 * da) - r2 * cos (angle + 2 * da); v2 = r1 * sin (angle + 3 * da) - r2 * sin (angle + 2 * da); currentNormal $= Normal3 v2 (-u2) 0 vertex (Vertex3 (r1 * cos (angle + 3 * da)) (r1 * sin (angle + 3 * da)) w ) vertex (Vertex3 (r1 * cos (angle + 3 * da)) (r1 * sin (angle + 3 * da)) (-w)) currentNormal $= Normal3 (cos angle) (sin angle) 0 else do vertex (Vertex3 (r1 * cos 0) (r1 * sin 0) w ) vertex (Vertex3 (r1 * cos 0) (r1 * sin 0) (-w)) -- draw inside radius cylinder gearInside :: Renderer gearInside r0 _ _ w _ _ _ angle = do currentNormal $= Normal3 (-cos angle) (-sin angle) 0 vertex (Vertex3 (r0 * cos angle) (r0 * sin angle) (-w)) vertex (Vertex3 (r0 * cos angle) (r0 * sin angle) w ) draw :: (DisplayList,DisplayList,DisplayList,Int) -> State -> IO () draw (gear1, gear2, gear3, autoexit) state = do clear [ ColorBuffer, DepthBuffer ] (x, y, z) <- get (viewRot state) a <- get (angle' state) let translatef = translate :: Vector3 GLfloat -> IO () preservingMatrix $ do rotate x (Vector3 1 0 0) rotate y (Vector3 0 1 0) rotate z (Vector3 0 0 1) preservingMatrix $ do translatef (Vector3 (-3) (-2) 0) rotate a (Vector3 0 0 1) callList gear1 preservingMatrix $ do translatef (Vector3 3.1 (-2) 0) rotate (-2 * a - 9) (Vector3 0 0 1) callList gear2 preservingMatrix $ do translatef (Vector3 (-3.1) 4.2 0) rotate (-2 * a - 25) (Vector3 0 0 1) callList gear3 swapBuffers frames state $~! (+1) t0' <- get (t0 state) t <- get elapsedTime when (t - t0' >= 5000) $ do f <- get (frames state) let seconds = fromIntegral (t - t0') / 1000 :: GLfloat fps = fromIntegral f / seconds putStrLn (show f ++ " frames in " ++ show seconds ++ " seconds = "++ show fps ++ " FPS") t0 state $= t frames state $= 0 when ((t >= 999 * autoexit) && (autoexit /= 0)) $ exitWith ExitSuccess idle :: State -> IdleCallback idle state = do angle' state $~! (+2) postRedisplay Nothing keyboard :: State -> KeyboardMouseCallback keyboard state (Char 'z') _ _ _ = modRot state ( 0, 0, 5) keyboard state (Char 'Z') _ _ _ = modRot state ( 0, 0, -5) keyboard state (SpecialKey KeyUp) _ _ _ = modRot state ( 5, 0, 0) keyboard state (SpecialKey KeyDown) _ _ _ = modRot state (-5, 0, 0) keyboard state (SpecialKey KeyLeft) _ _ _ = modRot state ( 0, 5, 0) keyboard state (SpecialKey KeyRight)_ _ _ = modRot state ( 0, -5, 0) keyboard _ (Char '\27') _ _ _ = exitWith ExitSuccess keyboard _ _ _ _ _ = return () modRot :: State -> View -> IO () modRot state (dx,dy,dz) = do (x, y, z) <- get (viewRot state) viewRot state $= (x + dx, y + dy, z + dz) postRedisplay Nothing -- new window size or exposure reshape :: ReshapeCallback reshape s@(Size width height) = do let h = fromIntegral height / fromIntegral width viewport $= (Position 0 0, s) matrixMode $= Projection loadIdentity frustum (-1) 1 (-h) h 5 60 matrixMode $= Modelview 0 loadIdentity translate (Vector3 0 0 (-40 :: GLfloat)) data Flag = GLInfo | AutoExit deriving ( Eq, Ord, Show ) argInfo :: [OptDescr Flag] argInfo = [ Option ['i'] ["info"] (NoArg GLInfo) "print gl information", Option ['e'] ["exit"] (NoArg AutoExit) "auto exit after 30 seconds" ] opts :: [String] -> IO [Flag] opts args = case getOpt Permute argInfo args of (o,_,[]) -> return o (_,_,errs) -> do putStr (concat errs ++ usageInfo "Usage: Gears [OPTION...]" argInfo) exitFailure info :: IO () info = do rendererStr <- get renderer putStrLn ("GL_RENDERER = " ++ rendererStr) vendorStr <- get vendor putStrLn ("GL_VENDOR = " ++ vendorStr) versionStr <- get glVersion putStrLn ("GL_VERSION = " ++ versionStr) exts <- get glExtensions putStrLn ("GL_EXTENSIONS = " ++ concat (intersperse " " exts)) myInit :: [String] -> IO (DisplayList,DisplayList,DisplayList,Int) myInit args = do position (Light 0) $= Vertex4 5 5 10 0 cullFace $= Just Back lighting $= Enabled light (Light 0) $= Enabled depthFunc $= Just Less -- make the gears g1 <- defineNewList Compile $ do materialAmbientAndDiffuse Front $= Color4 0.8 0.1 0.0 1.0 gear 1 4 1 20 0.7 g2 <- defineNewList Compile $ do materialAmbientAndDiffuse Front $= Color4 0.0 0.8 0.2 1.0 gear 0.5 2 2 10 0.7 g3 <- defineNewList Compile $ do materialAmbientAndDiffuse Front $= Color4 0.2 0.2 1.0 1.0 gear 1.3 2 0.5 10 0.7 normalize $= Enabled flags <- opts args when (GLInfo `elem` flags) info let autoexit = if AutoExit `elem` flags then 30 else 0 when (autoexit /= 0) $ putStrLn ("Auto Exit after " ++ show autoexit ++ " seconds.") return (g1, g2, g3, autoexit) visible :: State -> Visibility -> IO () visible state Visible = idleCallback $= Just (idle state) visible _ NotVisible = idleCallback $= Nothing main :: IO () main = do (_progName, args) <- getArgsAndInitialize initialDisplayMode $= [ RGBMode, WithDepthBuffer, DoubleBuffered ] initialWindowPosition $= Position 0 0 initialWindowSize $= Size 300 300 _ <- createWindow "Gears" state <- makeState gearsAndAuto <- myInit args displayCallback $= draw gearsAndAuto state reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboard state) visibilityCallback $= Just (visible state) mainLoop GLUT-2.7.0.16/examples/Misc/ExtractContours.hs0000644000000000000000000000765013255126367017144 0ustar0000000000000000{- ExtractContours.hs (adapted from tess.c which is (c) Silicon Graphics, Inc) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE This program demonstrates contour extraction. Two tesselated objects are drawn. The first is a rectangle with a triangular hole. The second is a smooth shaded, self-intersecting star. Note the exterior rectangle is drawn with its vertices in counter-clockwise order, but its interior clockwise. Note the combineCallback is needed for the self-intersecting star. Also note that removing the TessProperty for the star will make the interior unshaded (TessWindingOdd). -} import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT display :: [DisplayList] -> DisplayCallback display displayLists = do clear [ ColorBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () color3f (Color3 1 1 1) mapM_ callList displayLists flush -- 'Float' is a dummy, any marshalable type would do type DontCare = Float rectangle :: ComplexContour DontCare rectangle = ComplexContour [ AnnotatedVertex (Vertex3 50 50 0) 0, AnnotatedVertex (Vertex3 200 50 0) 0, AnnotatedVertex (Vertex3 200 200 0) 0, AnnotatedVertex (Vertex3 50 200 0) 0 ] tri :: ComplexContour DontCare tri = ComplexContour [ AnnotatedVertex (Vertex3 75 75 0) 0, AnnotatedVertex (Vertex3 125 175 0) 0, AnnotatedVertex (Vertex3 175 75 0) 0 ] rectAndTri :: ComplexPolygon DontCare rectAndTri = ComplexPolygon [ rectangle, tri ] noOpCombiner :: Combiner DontCare noOpCombiner _newVertex _weightedProperties = 0 star :: ComplexPolygon (Color3 GLfloat) star = ComplexPolygon [ ComplexContour [ AnnotatedVertex (Vertex3 250 50 0) (Color3 1 0 1), AnnotatedVertex (Vertex3 325 200 0) (Color3 1 1 0), AnnotatedVertex (Vertex3 400 50 0) (Color3 0 1 1), AnnotatedVertex (Vertex3 250 150 0) (Color3 1 0 0), AnnotatedVertex (Vertex3 400 150 0) (Color3 0 1 0) ] ] combineColors :: Combiner (Color3 GLfloat) combineColors _newVertex (WeightedProperties (w0, Color3 r0 g0 b0) (w1, Color3 r1 g1 b1) (w2, Color3 r2 g2 b2) (w3, Color3 r3 g3 b3)) = Color3 (w0*r0 + w1*r1 + w2*r2 + w3*r3) (w0*g0 + w1*g1 + w2*g2 + w3*g3) (w0*b0 + w1*b1 + w2*b2 + w3*b3) myInit :: IO [DisplayList] myInit = do clearColor $= Color4 0 0 0 0 rectAndTriList <- defineNewList Compile $ drawPolygonContours (\_ -> return ()) =<< extractContours TessWindingOdd 0 (Normal3 0 0 0) noOpCombiner rectAndTri starList <- defineNewList Compile $ drawPolygonContours color =<< extractContours TessWindingPositive 0 (Normal3 0 0 0) combineColors star return [ rectAndTriList, starList ] drawPolygonContours :: (v -> IO ()) -> PolygonContours v -> IO () drawPolygonContours colorHandler (PolygonContours simpleContours) = flip mapM_ simpleContours $ \(SimpleContour vertices) -> renderPrimitive LineLoop $ flip mapM_ vertices $ \(AnnotatedVertex plainVertex col) -> do colorHandler col vertex plainVertex reshape :: ReshapeCallback reshape size@(Size w h) = do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity ortho2D 0 (fromIntegral w) 0 (fromIntegral h) matrixMode $= Modelview 0 loadIdentity keyboard :: KeyboardMouseCallback keyboard (Char '\27') Down _ _ = exitWith ExitSuccess keyboard _ _ _ _ = return () main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ SingleBuffered, RGBMode ] initialWindowSize $= Size 500 500 _ <- createWindow progName displayLists <- myInit displayCallback $= display displayLists reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboard mainLoop GLUT-2.7.0.16/examples/Misc/ColorTriangle/ColorTriangle.hs0000644000000000000000000000673413255126367021307 0ustar0000000000000000{- ColorTriangle.hs (adapted from triangles.cpp which is (c) The Red Book Authors.) Copyright (c) Sven Panne 2018 This file is part of HOpenGL and distributed under a BSD-style license See the file GLUT/LICENSE A variation of Triangles.hs, adding colors to vertices via interleaved vertex attributes. -} import Control.Monad import Foreign.Marshal.Array import Foreign.Ptr import Foreign.Storable import Graphics.UI.GLUT import Prelude hiding ( init ) import LoadShaders bufferOffset :: Integral a => a -> Ptr b bufferOffset = plusPtr nullPtr . fromIntegral data Descriptor = Descriptor VertexArrayObject ArrayIndex NumArrayIndices data ColoredVertex = ColoredVertex (Vertex2 GLfloat) (Color3 GLfloat) instance Storable ColoredVertex where sizeOf ~(ColoredVertex v c) = sizeOf v + sizeOf c alignment ~(ColoredVertex v _) = alignment v peek ptr = do v <- peek (castPtr ptr) c <- peekByteOff (castPtr ptr) (sizeOf v) return $ ColoredVertex v c poke ptr (ColoredVertex v c) = do poke (castPtr ptr) v pokeByteOff (castPtr ptr) (sizeOf v) c init :: IO Descriptor init = do triangles <- genObjectName bindVertexArrayObject $= Just triangles let vertices = [ -- Triangle 1 ColoredVertex (Vertex2 (-0.90) (-0.90)) (Color3 1 0 0), ColoredVertex (Vertex2 0.85 (-0.90)) (Color3 0 1 0), ColoredVertex (Vertex2 (-0.90) 0.85 ) (Color3 0 0 1), -- Triangle 2 ColoredVertex (Vertex2 0.90 (-0.85)) (Color3 0 1 1), ColoredVertex (Vertex2 0.90 0.90 ) (Color3 1 0 1), ColoredVertex (Vertex2 (-0.85) 0.90 ) (Color3 1 1 0)] numVertices = length vertices vertexSize = sizeOf (head vertices) arrayBuffer <- genObjectName bindBuffer ArrayBuffer $= Just arrayBuffer withArray vertices $ \ptr -> do let size = fromIntegral (numVertices * vertexSize) bufferData ArrayBuffer $= (size, ptr, StaticDraw) program <- loadShaders [ ShaderInfo VertexShader (FileSource "color_triangles.vert"), ShaderInfo FragmentShader (FileSource "color_triangles.frag")] currentProgram $= Just program let firstIndex = 0 vPosition = AttribLocation 0 vColor = AttribLocation 1 vertexAttribPointer vPosition $= (ToFloat, VertexArrayDescriptor 2 Float (fromIntegral vertexSize) (bufferOffset (firstIndex * vertexSize))) vertexAttribArray vPosition $= Enabled let colorOffset = case head vertices of ~(ColoredVertex v _) -> sizeOf v vertexAttribPointer vColor $= (ToFloat, VertexArrayDescriptor 3 Float (fromIntegral vertexSize) (bufferOffset ((firstIndex * vertexSize) + fromIntegral colorOffset))) vertexAttribArray vColor $= Enabled return $ Descriptor triangles (fromIntegral firstIndex) (fromIntegral numVertices) display :: Descriptor -> DisplayCallback display (Descriptor triangles firstIndex numVertices) = do clear [ ColorBuffer ] bindVertexArrayObject $= Just triangles drawArrays Triangles firstIndex numVertices flush main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialDisplayMode $= [ RGBAMode ] initialWindowSize $= Size 512 512 initialContextVersion $= (4, 3) initialContextFlags $= [ DebugContext ] initialContextProfile $= [ CoreProfile ] _ <- createWindow progName descriptor <- init displayCallback $= display descriptor mainLoop GLUT-2.7.0.16/examples/Misc/ARBOcclude.hs0000644000000000000000000001232713255126367015675 0ustar0000000000000000{- ARBOcclude.hs (adapted from arbocclude.c which is (c) Brian Paul) Copyright (c) Sven Panne 2002-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE -} import Control.Monad ( unless, when ) import Data.IORef ( IORef, newIORef ) import System.Exit ( exitWith, ExitCode(ExitSuccess), exitFailure ) import Graphics.UI.GLUT data State = State { anim :: IORef Bool, xPos :: IORef GLfloat, sign :: IORef GLfloat, lastTime :: IORef Int } makeState :: IO State makeState = do a <- newIORef True x <- newIORef 0 s <- newIORef 1 l <- newIORef =<< get elapsedTime return $ State { anim = a, xPos = x, sign = s, lastTime = l } petrol, orange, white :: Color3 GLfloat petrol = Color3 0.0 0.6 0.8 orange = Color3 0.8 0.5 0.0 white = Color3 1.0 1.0 1.0 printString :: Vertex2 GLfloat -> String -> IO () printString pos s = do color white rasterPos pos renderString Fixed8By13 s idle :: State -> IdleCallback idle state = do time <- get elapsedTime l <- get (lastTime state) let timeDiff = fromIntegral (time - l) when (timeDiff >= 20) $ do -- 50Hz update lastTime state $= time s <- get (sign state) step state (timeDiff / 1000 * s) x <- get (xPos state) when (x > 2.5) $ do xPos state $= 2.5 sign state $= (-1) when (x < -2.5) $ do xPos state $= (-2.5) sign state $= 1 display :: QueryObject -> State -> DisplayCallback display occQuery state = do clear [ ColorBuffer, DepthBuffer ] matrixMode $= Projection loadIdentity frustum (-1) 1 (-1) 1 5 25 matrixMode $= Modelview 0 loadIdentity translate (Vector3 0 0 (-15 :: GLfloat)) drawOccludingPolygons -- draw the test polygon with occlusion testing passed <- preservingMatrix $ do x <- get (xPos state) translate (Vector3 x 0 (-0.5)) scale 0.3 0.3 (1.0 :: GLfloat) rotate (-90 * x) (Vector3 0 0 1) withQuery SamplesPassed occQuery $ do colorMask $= Color4 Disabled Disabled Disabled Disabled depthMask $= Disabled drawRect p <- waitForResult occQuery -- turn off occlusion testing colorMask $= Color4 Enabled Enabled Enabled Enabled depthMask $= Enabled -- draw the orange rect, so we can see what's going on color orange drawRect return p -- Print result message matrixMode $= Projection loadIdentity ortho (-1) 1 (-1) 1 (-1) 1 matrixMode $= Modelview 0 loadIdentity printString (Vertex2 (-0.50) (-0.7)) (" " ++ flushRight 4 passed ++ " Fragments Visible") when (passed == 0) $ printString (Vertex2 (-0.25) (-0.8)) "Fully Occluded" swapBuffers drawOccludingPolygons :: IO () drawOccludingPolygons = do color petrol drawQuads [ Vertex2 (-1.6) (-1.5), Vertex2 (-0.4) (-1.5), Vertex2 (-0.4) 1.5 , Vertex2 (-1.6) 1.5 , Vertex2 0.4 (-1.5), Vertex2 1.6 (-1.5), Vertex2 1.6 1.5 , Vertex2 0.4 1.5 ] drawRect :: IO () drawRect = do drawQuads [ Vertex2 (-1) (-1), Vertex2 1 (-1), Vertex2 1 1 , Vertex2 (-1) 1 ] drawQuads :: [Vertex2 GLfloat] -> IO () drawQuads = renderPrimitive Quads . mapM_ vertex waitForResult :: QueryObject -> IO GLuint waitForResult occQuery = do let loop = do -- do useful work here, if any ready <- get (queryResultAvailable occQuery) unless ready loop loop get (queryResult occQuery) flushRight :: Show a => Int -> a -> String flushRight width x = replicate (width - length s) ' ' ++ s where s = show x keyboard :: State -> KeyboardMouseCallback keyboard _ (Char '\27') Down _ _ = exitWith ExitSuccess keyboard state (Char ' ') Down _ _ = do anim state $~ not setIdleCallback state keyboard state (SpecialKey KeyLeft) Down _ _ = step state (-0.1) keyboard state (SpecialKey KeyRight) Down _ _ = step state 0.1 keyboard _ _ _ _ _ = return () setIdleCallback :: State -> IO () setIdleCallback state = do a <- get (anim state) idleCallback $= if a then Just (idle state) else Nothing step :: State -> GLfloat -> IO () step state s = do xPos state $~ (+ s) postRedisplay Nothing myInit :: IO () myInit = do exts <- get glExtensions unless ("GL_ARB_occlusion_query" `elem` exts) $ do putStrLn "Sorry, this demo requires the GL_ARB_occlusion_query extension." exitFailure bits <- get (queryCounterBits SamplesPassed) unless (bits > 0) $ do putStrLn "Hmmm, GL_QUERY_COUNTER_BITS_ARB is zero!" exitFailure depthFunc $= Just Less main :: IO () main = do (progName, _args) <- getArgsAndInitialize initialWindowPosition $= Position 0 0 initialWindowSize $= Size 400 400 initialDisplayMode $= [ RGBMode, DoubleBuffered, WithDepthBuffer ] _ <- createWindow progName state <- makeState reshapeCallback $= Just (\size -> viewport $= (Position 0 0, size)) keyboardMouseCallback $= Just (keyboard state) setIdleCallback state occQuery <- genObjectName displayCallback $= display occQuery state myInit mainLoop GLUT-2.7.0.16/examples/BOGLGP/Chapter03/TrianglesQuads.hs0000644000000000000000000002257113255126367020532 0ustar0000000000000000{- TrianglesQuads.hs (adapted from TrianglesQuads which is (c) 2004 Astle/Hawkins) Copyright (c) Sven Panne 2004-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE -} import Control.Monad ( when, unless ) import Data.Maybe ( isJust ) import Graphics.UI.GLUT hiding ( initialize ) import System.Console.GetOpt import System.Environment ( getProgName ) import System.Exit ( exitWith, ExitCode(..) ) import System.IO ( hPutStr, stderr ) -------------------------------------------------------------------------------- -- Setup GLUT and OpenGL, drop into the event loop. -------------------------------------------------------------------------------- main :: IO () main = do -- Setup the basic GLUT stuff (_, args) <- getArgsAndInitialize opts <- parseOptions args initialDisplayMode $= [ DoubleBuffered, RGBMode, WithDepthBuffer ] (if useFullscreen opts then fullscreenMode else windowedMode) opts initialize -- Register the event callback functions displayCallback $= do render; swapBuffers reshapeCallback $= Just setupProjection keyboardMouseCallback $= Just keyboardMouseHandler -- No need for an idle callback here, this would just hog the CPU -- without any visible effect -- At this point, control is relinquished to the GLUT event handler. -- Control is returned as events occur, via the callback functions. mainLoop fullscreenMode :: Options -> IO () fullscreenMode opts = do let addCapability c = maybe id (\x -> (Where' c IsEqualTo x :)) gameModeCapabilities $= (addCapability GameModeWidth (Just (windowWidth opts)) . addCapability GameModeHeight (Just (windowHeight opts)) . addCapability GameModeBitsPerPlane (bpp opts) . addCapability GameModeRefreshRate (refreshRate opts)) [] _ <- enterGameMode maybeWin <- get currentWindow if isJust maybeWin then cursor $= None else do hPutStr stderr "Could not enter fullscreen mode, using windowed mode\n" windowedMode (opts { useFullscreen = False } ) windowedMode :: Options -> IO () windowedMode opts = do initialWindowSize $= Size (fromIntegral (windowWidth opts)) (fromIntegral (windowHeight opts)) _ <- createWindow "BOGLGP - Chapter 3 - TrianglesQuads" return () -------------------------------------------------------------------------------- -- Option handling -------------------------------------------------------------------------------- data Options = Options { useFullscreen :: Bool, windowWidth :: Int, windowHeight :: Int, bpp :: Maybe Int, refreshRate :: Maybe Int } startOpt :: Options startOpt = Options { useFullscreen = False, windowWidth = 800, windowHeight = 600, bpp = Nothing, refreshRate = Nothing } options :: [OptDescr (Options -> IO Options)] options = [ Option ['f'] ["fullscreen"] (NoArg (\opt -> return opt { useFullscreen = True })) "use fullscreen mode if possible", Option ['w'] ["width"] (ReqArg (\arg opt -> do w <- readInt "WIDTH" arg return opt { windowWidth = w }) "WIDTH") "use window width WIDTH", Option ['h'] ["height"] (ReqArg (\arg opt -> do h <- readInt "HEIGHT" arg return opt { windowHeight = h }) "HEIGHT") "use window height HEIGHT", Option ['b'] ["bpp"] (ReqArg (\arg opt -> do b <- readInt "BPP" arg return opt { bpp = Just b }) "BPP") "use BPP bits per plane (ignored in windowed mode)", Option ['r'] ["refresh-rate"] (ReqArg (\arg opt -> do r <- readInt "HZ" arg return opt { refreshRate = Just r }) "HZ") "use refresh rate HZ (ignored in windowed mode)", Option ['?'] ["help"] (NoArg (\_ -> do usage >>= putStr safeExitWith ExitSuccess)) "show help" ] readInt :: String -> String -> IO Int readInt name arg = case reads arg of ((x,[]) : _) -> return x _ -> dieWith ["Can't parse " ++ name ++ " argument '" ++ arg ++ "'\n"] usage :: IO String usage = do progName <- getProgName return $ usageInfo ("Usage: " ++ progName ++ " [OPTION...]") options parseOptions :: [String] -> IO Options parseOptions args = do let (optsActions, nonOptions, errs) = getOpt Permute options args unless (null nonOptions && null errs) (dieWith errs) foldl (>>=) (return startOpt) optsActions dieWith :: [String] -> IO a dieWith errs = do u <- usage mapM_ (hPutStr stderr) (errs ++ [u]) safeExitWith (ExitFailure 1) -------------------------------------------------------------------------------- -- Handle mouse and keyboard events. For this simple demo, just exit when -- ESCAPE is pressed. -------------------------------------------------------------------------------- keyboardMouseHandler :: KeyboardMouseCallback keyboardMouseHandler (Char '\27') Down _ _ = safeExitWith ExitSuccess keyboardMouseHandler _ _ _ _ = return () safeExitWith :: ExitCode -> IO a safeExitWith code = do gma <- get gameModeActive when gma leaveGameMode exitWith code -------------------------------------------------------------------------------- -- Do one time setup, i.e. set the clear color. -------------------------------------------------------------------------------- initialize :: IO () initialize = clearColor $= Color4 0 0 0 0 -------------------------------------------------------------------------------- -- Reset the viewport for window changes. -------------------------------------------------------------------------------- setupProjection :: ReshapeCallback setupProjection (Size width height) = do -- don't want a divide by zero let h = max 1 height -- reset the viewport to new dimensions viewport $= (Position 0 0, Size width h) -- set projection matrix as the current matrix matrixMode $= Projection -- reset projection matrix loadIdentity -- calculate aspect ratio of window perspective 52 (fromIntegral width / fromIntegral h) 1 1000 -- set modelview matrix matrixMode $= Modelview 0 -- reset modelview matrix loadIdentity -------------------------------------------------------------------------------- -- Clear and redraw the scene. -------------------------------------------------------------------------------- render :: DisplayCallback render = do -- clear screen and depth buffer clear [ ColorBuffer, DepthBuffer ] loadIdentity lookAt (Vertex3 0 10 0.1) (Vertex3 0 0 0) (Vector3 0 1 0) -- resolve overloading, not needed in "real" programs let translate3f = translate :: Vector3 GLfloat -> IO () -- top left preservingMatrix $ do translate3f (Vector3 (-6) 0 (-4)) drawPoints -- top middle preservingMatrix $ do polygonMode $= (Fill, Fill) translate3f (Vector3 (-2) 0 (-4)) drawTriangles -- top right preservingMatrix $ do polygonMode $= (Line, Line) translate3f (Vector3 2 0 (-4)) drawQuads -- bottom left preservingMatrix $ do polygonMode $= (Line, Line) translate3f (Vector3 (-6) 0 0.5) drawTriangleStrip -- bottom middle preservingMatrix $ do polygonMode $= (Line, Line) translate3f (Vector3 (-2) 0 0.5) drawTriangleFan -- bottom right preservingMatrix $ do polygonMode $= (Line, Line) translate3f (Vector3 2 0 0.5) drawQuadStrip -- Hello, this is C... :-) for :: [GLfloat] -> (GLfloat -> IO ()) -> IO () for = flip mapM_ -- draw grid of points showing dataset we are working with drawPoints :: IO () drawPoints = do pointSize $= 4 renderPrimitive Points $ for [ 0 .. 3 ] $ \x -> for [ 0 .. 3 ] $ \z -> vertex (Vertex3 x 0 z) -- draw grid as individual triangles drawTriangles :: IO () drawTriangles = renderPrimitive Triangles $ for [ 0 .. 2 ] $ \x -> for [ 0 .. 2 ] $ \z -> do vertex (Vertex3 x 0 z ) vertex (Vertex3 (x + 1) 0 z ) vertex (Vertex3 x 0 (z + 1)) -- draw grid as triangle fan drawTriangleFan :: IO () drawTriangleFan = renderPrimitive TriangleFan $ do -- center vertex of fan vertex (Vertex3 0 0 (0 :: GLfloat)) -- bottom side for [ 3, 2 .. 0 ] $ \x -> vertex (Vertex3 x 0 3) -- right side for [ 3, 2 .. 0 ] $ \z -> vertex (Vertex3 3 0 z) -- draw grid as triangle strips drawTriangleStrip :: IO () drawTriangleStrip = -- 3 rows of triangle strips for [ 0 .. 2 ] $ \x -> renderPrimitive TriangleStrip $ for [ 0 .. 2 ] $ \z -> do vertex (Vertex3 x 0 z ) vertex (Vertex3 (x + 1) 0 z ) vertex (Vertex3 x 0 (z + 1)) vertex (Vertex3 (x + 1) 0 (z + 1)) -- draw grid as individual quads drawQuads :: IO () drawQuads = renderPrimitive Quads $ for [ 0 .. 2 ] $ \x -> for [ 0 .. 2 ] $ \z -> do vertex (Vertex3 x 0 z ) vertex (Vertex3 (x + 1) 0 z ) vertex (Vertex3 (x + 1) 0 (z + 1)) vertex (Vertex3 x 0 (z + 1)) -- draw grid as quad strips drawQuadStrip :: IO () drawQuadStrip = for [ 0 .. 2 ] $ \x -> renderPrimitive QuadStrip $ for [ 0 .. 3 ] $ \z -> do vertex (Vertex3 x 0 z) vertex (Vertex3 (x + 1) 0 z) GLUT-2.7.0.16/examples/BOGLGP/Chapter03/Polygons.hs0000644000000000000000000002017513255126367017414 0ustar0000000000000000{- Polygons.hs (adapted from Polygons which is (c) 2004 Astle/Hawkins) Copyright (c) Sven Panne 2004-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE -} import Control.Monad ( when, unless ) import Data.IORef ( IORef, newIORef ) import Data.Maybe ( isJust ) import Graphics.UI.GLUT hiding ( initialize ) import System.Console.GetOpt import System.Environment ( getProgName ) import System.Exit ( exitWith, ExitCode(..) ) import System.IO ( hPutStr, stderr ) -------------------------------------------------------------------------------- -- Setup GLUT and OpenGL, drop into the event loop. -------------------------------------------------------------------------------- main :: IO () main = do -- Setup the basic GLUT stuff (_, args) <- getArgsAndInitialize opts <- parseOptions args initialDisplayMode $= [ DoubleBuffered, RGBMode, WithDepthBuffer ] (if useFullscreen opts then fullscreenMode else windowedMode) opts state <- initialize -- Register the event callback functions displayCallback $= do render state; swapBuffers reshapeCallback $= Just setupProjection keyboardMouseCallback $= Just keyboardMouseHandler idleCallback $= Just (postRedisplay Nothing) -- At this point, control is relinquished to the GLUT event handler. -- Control is returned as events occur, via the callback functions. mainLoop fullscreenMode :: Options -> IO () fullscreenMode opts = do let addCapability c = maybe id (\x -> (Where' c IsEqualTo x :)) gameModeCapabilities $= (addCapability GameModeWidth (Just (windowWidth opts)) . addCapability GameModeHeight (Just (windowHeight opts)) . addCapability GameModeBitsPerPlane (bpp opts) . addCapability GameModeRefreshRate (refreshRate opts)) [] _ <- enterGameMode maybeWin <- get currentWindow if isJust maybeWin then cursor $= None else do hPutStr stderr "Could not enter fullscreen mode, using windowed mode\n" windowedMode (opts { useFullscreen = False } ) windowedMode :: Options -> IO () windowedMode opts = do initialWindowSize $= Size (fromIntegral (windowWidth opts)) (fromIntegral (windowHeight opts)) _ <- createWindow "BOGLGP - Chapter 3 - Polygons" return () -------------------------------------------------------------------------------- -- Option handling -------------------------------------------------------------------------------- data Options = Options { useFullscreen :: Bool, windowWidth :: Int, windowHeight :: Int, bpp :: Maybe Int, refreshRate :: Maybe Int } startOpt :: Options startOpt = Options { useFullscreen = False, windowWidth = 800, windowHeight = 600, bpp = Nothing, refreshRate = Nothing } options :: [OptDescr (Options -> IO Options)] options = [ Option ['f'] ["fullscreen"] (NoArg (\opt -> return opt { useFullscreen = True })) "use fullscreen mode if possible", Option ['w'] ["width"] (ReqArg (\arg opt -> do w <- readInt "WIDTH" arg return opt { windowWidth = w }) "WIDTH") "use window width WIDTH", Option ['h'] ["height"] (ReqArg (\arg opt -> do h <- readInt "HEIGHT" arg return opt { windowHeight = h }) "HEIGHT") "use window height HEIGHT", Option ['b'] ["bpp"] (ReqArg (\arg opt -> do b <- readInt "BPP" arg return opt { bpp = Just b }) "BPP") "use BPP bits per plane (ignored in windowed mode)", Option ['r'] ["refresh-rate"] (ReqArg (\arg opt -> do r <- readInt "HZ" arg return opt { refreshRate = Just r }) "HZ") "use refresh rate HZ (ignored in windowed mode)", Option ['?'] ["help"] (NoArg (\_ -> do usage >>= putStr safeExitWith ExitSuccess)) "show help" ] readInt :: String -> String -> IO Int readInt name arg = case reads arg of ((x,[]) : _) -> return x _ -> dieWith ["Can't parse " ++ name ++ " argument '" ++ arg ++ "'\n"] usage :: IO String usage = do progName <- getProgName return $ usageInfo ("Usage: " ++ progName ++ " [OPTION...]") options parseOptions :: [String] -> IO Options parseOptions args = do let (optsActions, nonOptions, errs) = getOpt Permute options args unless (null nonOptions && null errs) (dieWith errs) foldl (>>=) (return startOpt) optsActions dieWith :: [String] -> IO a dieWith errs = do u <- usage mapM_ (hPutStr stderr) (errs ++ [u]) safeExitWith (ExitFailure 1) -------------------------------------------------------------------------------- -- Handle mouse and keyboard events. For this simple demo, just exit when -- ESCAPE is pressed. -------------------------------------------------------------------------------- keyboardMouseHandler :: KeyboardMouseCallback keyboardMouseHandler (Char '\27') Down _ _ = safeExitWith ExitSuccess keyboardMouseHandler _ _ _ _ = return () safeExitWith :: ExitCode -> IO a safeExitWith code = do gma <- get gameModeActive when gma leaveGameMode exitWith code -------------------------------------------------------------------------------- -- The globale state, which is only the current angle in this simple demo. -- We don't need the window dimensions here, they are not used and would -- be easily available via GLUT anyway. -------------------------------------------------------------------------------- data State = State { angle :: IORef GLfloat } makeState :: IO State makeState = do a <- newIORef 0 return $ State { angle = a } -------------------------------------------------------------------------------- -- Do one time setup, i.e. set the clear color and create the global state. -- Note that there is no need to set the polygon mode here, because we always -- set the front and back mode together. -------------------------------------------------------------------------------- initialize :: IO State initialize = do -- clear to black background clearColor $= Color4 0 0 0 0 makeState -------------------------------------------------------------------------------- -- Reset the viewport for window changes. -------------------------------------------------------------------------------- setupProjection :: ReshapeCallback setupProjection (Size width height) = do -- don't want a divide by zero let h = max 1 height -- reset the viewport to new dimensions viewport $= (Position 0 0, Size width h) -- set projection matrix as the current matrix matrixMode $= Projection -- reset projection matrix loadIdentity -- calculate aspect ratio of window perspective 52 (fromIntegral width / fromIntegral h) 1 1000 -- set modelview matrix matrixMode $= Modelview 0 -- reset modelview matrix loadIdentity -------------------------------------------------------------------------------- -- Clear and redraw the scene. -------------------------------------------------------------------------------- render :: State -> DisplayCallback render state = do -- clear screen and depth buffer clear [ ColorBuffer, DepthBuffer ] loadIdentity lookAt (Vertex3 0 10 0.1) (Vertex3 0 0 0) (Vector3 0 1 0) a <- get (angle state) mapM_ (draw2DSquare a) [ (Line, Fill, -4, Color3 1 0 0), (Fill, Point, -2, Color3 0 1 0), (Fill, Fill, 0, Color3 0 0 1), (Fill, Line, 2, Color3 1 0 1), (Line, Line, 4, Color3 1 1 0)] angle state $~ (+ 0.2) draw2DSquare :: GLfloat -> (PolygonMode, PolygonMode, GLfloat, Color3 GLfloat) -> IO () draw2DSquare a (polygonModeFront, polygonModeBack, deltaX, c) = do polygonMode $= (polygonModeFront, polygonModeBack) preservingMatrix $ do translate (Vector3 deltaX 0 0) rotate a (Vector3 0 0 1) color c renderPrimitive Polygon $ do -- resolve overloading, not needed in "real" programs let vertex3f = vertex :: Vertex3 GLfloat -> IO () vertex3f (Vertex3 (-0.5) 0 0 ) vertex3f (Vertex3 0.5 0 0 ) vertex3f (Vertex3 0.5 0 (-1)) vertex3f (Vertex3 (-0.5) 0 (-1)) GLUT-2.7.0.16/examples/BOGLGP/Chapter03/Points.hs0000644000000000000000000001547313255126367017063 0ustar0000000000000000{- Points.hs (adapted from Points which is (c) 2004 Astle/Hawkins) Copyright (c) Sven Panne 2004-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE -} import Control.Monad ( when, unless, zipWithM_ ) import Data.Maybe ( isJust ) import Graphics.UI.GLUT hiding ( initialize ) import System.Console.GetOpt import System.Environment ( getProgName ) import System.Exit ( exitWith, ExitCode(..) ) import System.IO ( hPutStr, stderr ) -------------------------------------------------------------------------------- -- Setup GLUT and OpenGL, drop into the event loop. -------------------------------------------------------------------------------- main :: IO () main = do -- Setup the basic GLUT stuff (_, args) <- getArgsAndInitialize opts <- parseOptions args initialDisplayMode $= [ DoubleBuffered, RGBMode, WithDepthBuffer ] (if useFullscreen opts then fullscreenMode else windowedMode) opts initialize -- Register the event callback functions displayCallback $= do render; swapBuffers reshapeCallback $= Just setupProjection keyboardMouseCallback $= Just keyboardMouseHandler -- No need for an idle callback here, this would just hog the CPU -- without any visible effect -- At this point, control is relinquished to the GLUT event handler. -- Control is returned as events occur, via the callback functions. mainLoop fullscreenMode :: Options -> IO () fullscreenMode opts = do let addCapability c = maybe id (\x -> (Where' c IsEqualTo x :)) gameModeCapabilities $= (addCapability GameModeWidth (Just (windowWidth opts)) . addCapability GameModeHeight (Just (windowHeight opts)) . addCapability GameModeBitsPerPlane (bpp opts) . addCapability GameModeRefreshRate (refreshRate opts)) [] _ <- enterGameMode maybeWin <- get currentWindow if isJust maybeWin then cursor $= None else do hPutStr stderr "Could not enter fullscreen mode, using windowed mode\n" windowedMode (opts { useFullscreen = False } ) windowedMode :: Options -> IO () windowedMode opts = do initialWindowSize $= Size (fromIntegral (windowWidth opts)) (fromIntegral (windowHeight opts)) _ <- createWindow "BOGLGP - Chapter 3 - Points" return () -------------------------------------------------------------------------------- -- Option handling -------------------------------------------------------------------------------- data Options = Options { useFullscreen :: Bool, windowWidth :: Int, windowHeight :: Int, bpp :: Maybe Int, refreshRate :: Maybe Int } startOpt :: Options startOpt = Options { useFullscreen = False, windowWidth = 800, windowHeight = 600, bpp = Nothing, refreshRate = Nothing } options :: [OptDescr (Options -> IO Options)] options = [ Option ['f'] ["fullscreen"] (NoArg (\opt -> return opt { useFullscreen = True })) "use fullscreen mode if possible", Option ['w'] ["width"] (ReqArg (\arg opt -> do w <- readInt "WIDTH" arg return opt { windowWidth = w }) "WIDTH") "use window width WIDTH", Option ['h'] ["height"] (ReqArg (\arg opt -> do h <- readInt "HEIGHT" arg return opt { windowHeight = h }) "HEIGHT") "use window height HEIGHT", Option ['b'] ["bpp"] (ReqArg (\arg opt -> do b <- readInt "BPP" arg return opt { bpp = Just b }) "BPP") "use BPP bits per plane (ignored in windowed mode)", Option ['r'] ["refresh-rate"] (ReqArg (\arg opt -> do r <- readInt "HZ" arg return opt { refreshRate = Just r }) "HZ") "use refresh rate HZ (ignored in windowed mode)", Option ['?'] ["help"] (NoArg (\_ -> do usage >>= putStr safeExitWith ExitSuccess)) "show help" ] readInt :: String -> String -> IO Int readInt name arg = case reads arg of ((x,[]) : _) -> return x _ -> dieWith ["Can't parse " ++ name ++ " argument '" ++ arg ++ "'\n"] usage :: IO String usage = do progName <- getProgName return $ usageInfo ("Usage: " ++ progName ++ " [OPTION...]") options parseOptions :: [String] -> IO Options parseOptions args = do let (optsActions, nonOptions, errs) = getOpt Permute options args unless (null nonOptions && null errs) (dieWith errs) foldl (>>=) (return startOpt) optsActions dieWith :: [String] -> IO a dieWith errs = do u <- usage mapM_ (hPutStr stderr) (errs ++ [u]) safeExitWith (ExitFailure 1) -------------------------------------------------------------------------------- -- Handle mouse and keyboard events. For this simple demo, just exit when -- ESCAPE is pressed. -------------------------------------------------------------------------------- keyboardMouseHandler :: KeyboardMouseCallback keyboardMouseHandler (Char '\27') Down _ _ = safeExitWith ExitSuccess keyboardMouseHandler _ _ _ _ = return () safeExitWith :: ExitCode -> IO a safeExitWith code = do gma <- get gameModeActive when gma leaveGameMode exitWith code -------------------------------------------------------------------------------- -- Do one time setup, i.e. set the clear color. -------------------------------------------------------------------------------- initialize :: IO () initialize = clearColor $= Color4 0 0 0 0 -------------------------------------------------------------------------------- -- Reset the viewport for window changes. -------------------------------------------------------------------------------- setupProjection :: ReshapeCallback setupProjection (Size width height) = do -- don't want a divide by zero let h = max 1 height -- reset the viewport to new dimensions viewport $= (Position 0 0, Size width h) -- set projection matrix as the current matrix matrixMode $= Projection -- reset projection matrix loadIdentity -- calculate aspect ratio of window perspective 52 (fromIntegral width / fromIntegral h) 1 1000 -- set modelview matrix matrixMode $= Modelview 0 -- reset modelview matrix loadIdentity -------------------------------------------------------------------------------- -- Clear and redraw the scene. -------------------------------------------------------------------------------- render :: DisplayCallback render = do -- clear screen and depth buffer clear [ ColorBuffer, DepthBuffer ] loadIdentity lookAt (Vertex3 0 6 0.1) (Vertex3 0 0 0) (Vector3 0 1 0) -- draw a line of points of increasing size zipWithM_ (\ps point -> do -- set the point size pointSize $= ps -- draw the point renderPrimitive Points $ vertex (Vertex3 point 0 0)) [ 0.5 .. ] [ -4, -3.5 .. 4.5 :: GLfloat ] GLUT-2.7.0.16/examples/BOGLGP/Chapter03/OnYourOwn1.hs0000644000000000000000000001706713255126367017610 0ustar0000000000000000{- OnYourOwn1.hs (adapted from OnYourOwn1 which is (c) 2004 Astle/Hawkins) Copyright (c) Sven Panne 2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE -} import Control.Monad ( when, unless ) import Data.Maybe ( isJust ) import Graphics.UI.GLUT hiding ( initialize ) import System.Console.GetOpt import System.Environment ( getProgName ) import System.Exit ( exitWith, ExitCode(..) ) import System.IO ( hPutStr, stderr ) -------------------------------------------------------------------------------- -- Setup GLUT and OpenGL, drop into the event loop. -------------------------------------------------------------------------------- main :: IO () main = do -- Setup the basic GLUT stuff (_, args) <- getArgsAndInitialize opts <- parseOptions args initialDisplayMode $= [ DoubleBuffered, RGBMode, WithDepthBuffer ] (if useFullscreen opts then fullscreenMode else windowedMode) opts initialize -- Register the event callback functions displayCallback $= do render; swapBuffers reshapeCallback $= Just setupProjection keyboardMouseCallback $= Just keyboardMouseHandler -- No need for an idle callback here, this would just hog the CPU -- without any visible effect -- At this point, control is relinquished to the GLUT event handler. -- Control is returned as events occur, via the callback functions. mainLoop fullscreenMode :: Options -> IO () fullscreenMode opts = do let addCapability c = maybe id (\x -> (Where' c IsEqualTo x :)) gameModeCapabilities $= (addCapability GameModeWidth (Just (windowWidth opts)) . addCapability GameModeHeight (Just (windowHeight opts)) . addCapability GameModeBitsPerPlane (bpp opts) . addCapability GameModeRefreshRate (refreshRate opts)) [] _ <- enterGameMode maybeWin <- get currentWindow if isJust maybeWin then cursor $= None else do hPutStr stderr "Could not enter fullscreen mode, using windowed mode\n" windowedMode (opts { useFullscreen = False } ) windowedMode :: Options -> IO () windowedMode opts = do initialWindowSize $= Size (fromIntegral (windowWidth opts)) (fromIntegral (windowHeight opts)) _ <- createWindow "BOGLGP - Chapter 3 - On Your Own 1" return () -------------------------------------------------------------------------------- -- Option handling -------------------------------------------------------------------------------- data Options = Options { useFullscreen :: Bool, windowWidth :: Int, windowHeight :: Int, bpp :: Maybe Int, refreshRate :: Maybe Int } startOpt :: Options startOpt = Options { useFullscreen = False, windowWidth = 800, windowHeight = 600, bpp = Nothing, refreshRate = Nothing } options :: [OptDescr (Options -> IO Options)] options = [ Option ['f'] ["fullscreen"] (NoArg (\opt -> return opt { useFullscreen = True })) "use fullscreen mode if possible", Option ['w'] ["width"] (ReqArg (\arg opt -> do w <- readInt "WIDTH" arg return opt { windowWidth = w }) "WIDTH") "use window width WIDTH", Option ['h'] ["height"] (ReqArg (\arg opt -> do h <- readInt "HEIGHT" arg return opt { windowHeight = h }) "HEIGHT") "use window height HEIGHT", Option ['b'] ["bpp"] (ReqArg (\arg opt -> do b <- readInt "BPP" arg return opt { bpp = Just b }) "BPP") "use BPP bits per plane (ignored in windowed mode)", Option ['r'] ["refresh-rate"] (ReqArg (\arg opt -> do r <- readInt "HZ" arg return opt { refreshRate = Just r }) "HZ") "use refresh rate HZ (ignored in windowed mode)", Option ['?'] ["help"] (NoArg (\_ -> do usage >>= putStr safeExitWith ExitSuccess)) "show help" ] readInt :: String -> String -> IO Int readInt name arg = case reads arg of ((x,[]) : _) -> return x _ -> dieWith ["Can't parse " ++ name ++ " argument '" ++ arg ++ "'\n"] usage :: IO String usage = do progName <- getProgName return $ usageInfo ("Usage: " ++ progName ++ " [OPTION...]") options parseOptions :: [String] -> IO Options parseOptions args = do let (optsActions, nonOptions, errs) = getOpt Permute options args unless (null nonOptions && null errs) (dieWith errs) foldl (>>=) (return startOpt) optsActions dieWith :: [String] -> IO a dieWith errs = do u <- usage mapM_ (hPutStr stderr) (errs ++ [u]) safeExitWith (ExitFailure 1) -------------------------------------------------------------------------------- -- Handle mouse and keyboard events. For this simple demo, just exit when -- ESCAPE is pressed. -------------------------------------------------------------------------------- keyboardMouseHandler :: KeyboardMouseCallback keyboardMouseHandler (Char '\27') Down _ _ = safeExitWith ExitSuccess keyboardMouseHandler _ _ _ _ = return () safeExitWith :: ExitCode -> IO a safeExitWith code = do gma <- get gameModeActive when gma leaveGameMode exitWith code -------------------------------------------------------------------------------- -- Do one time setup, i.e. set the clear color. -------------------------------------------------------------------------------- initialize :: IO () initialize = do -- clear to black background clearColor $= Color4 0 0 0 0 -------------------------------------------------------------------------------- -- Reset the viewport for window changes. -------------------------------------------------------------------------------- setupProjection :: ReshapeCallback setupProjection (Size width height) = do -- don't want a divide by zero let h = max 1 height -- reset the viewport to new dimensions viewport $= (Position 0 0, Size width h) -- set projection matrix as the current matrix matrixMode $= Projection -- reset projection matrix loadIdentity -- calculate aspect ratio of window perspective 52 (fromIntegral width / fromIntegral h) 1 1000 -- set modelview matrix matrixMode $= Modelview 0 -- reset modelview matrix loadIdentity -------------------------------------------------------------------------------- -- Clear and redraw the scene. -------------------------------------------------------------------------------- render :: DisplayCallback render = do -- clear screen and depth buffer clear [ ColorBuffer, DepthBuffer ] loadIdentity lookAt (Vertex3 0 10 0.1) (Vertex3 0 0 0) (Vector3 0 1 0) -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () color3f (Color3 1 1 1) drawCircleApproximation 2 10 False -- Hello, this is C... :-) for :: [GLint] -> (GLint -> IO ()) -> IO () for = flip mapM_ drawCircleApproximation :: GLfloat -> GLint -> Bool -> IO () drawCircleApproximation radius numberOfSides edgeOnly = -- if edge only, use line strips; otherwise, use polygons renderPrimitive (if edgeOnly then LineStrip else Polygon) $ do -- calculate each vertex on the circle for [ 0 .. numberOfSides - 1 ] $ \v -> do -- calculate the angle of the current vertex let angle = fromIntegral v * 2 * pi / fromIntegral numberOfSides -- draw the current vertex at the correct radius vertex (Vertex3 (cos angle * radius) 0 (sin angle * radius)) -- if drawing edge only, then need to complete the loop with first vertex when edgeOnly $ vertex (Vertex3 radius 0 0) GLUT-2.7.0.16/examples/BOGLGP/Chapter03/Lines.hs0000644000000000000000000001635313255126367016657 0ustar0000000000000000{- Lines.hs (adapted from Lines which is (c) 2004 Astle/Hawkins) Copyright (c) Sven Panne 2004-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE -} import Control.Monad ( when, unless, zipWithM_ ) import Data.Maybe ( isJust ) import Graphics.UI.GLUT hiding ( initialize ) import System.Console.GetOpt import System.Environment ( getProgName ) import System.Exit ( exitWith, ExitCode(..) ) import System.IO ( hPutStr, stderr ) -------------------------------------------------------------------------------- -- Setup GLUT and OpenGL, drop into the event loop. -------------------------------------------------------------------------------- main :: IO () main = do -- Setup the basic GLUT stuff (_, args) <- getArgsAndInitialize opts <- parseOptions args initialDisplayMode $= [ DoubleBuffered, RGBMode, WithDepthBuffer ] (if useFullscreen opts then fullscreenMode else windowedMode) opts initialize -- Register the event callback functions displayCallback $= do render; swapBuffers reshapeCallback $= Just setupProjection keyboardMouseCallback $= Just keyboardMouseHandler -- No need for an idle callback here, this would just hog the CPU -- without any visible effect -- At this point, control is relinquished to the GLUT event handler. -- Control is returned as events occur, via the callback functions. mainLoop fullscreenMode :: Options -> IO () fullscreenMode opts = do let addCapability c = maybe id (\x -> (Where' c IsEqualTo x :)) gameModeCapabilities $= (addCapability GameModeWidth (Just (windowWidth opts)) . addCapability GameModeHeight (Just (windowHeight opts)) . addCapability GameModeBitsPerPlane (bpp opts) . addCapability GameModeRefreshRate (refreshRate opts)) [] _ <- enterGameMode maybeWin <- get currentWindow if isJust maybeWin then cursor $= None else do hPutStr stderr "Could not enter fullscreen mode, using windowed mode\n" windowedMode (opts { useFullscreen = False } ) windowedMode :: Options -> IO () windowedMode opts = do initialWindowSize $= Size (fromIntegral (windowWidth opts)) (fromIntegral (windowHeight opts)) _ <- createWindow "BOGLGP - Chapter 3 - Lines" return () -------------------------------------------------------------------------------- -- Option handling -------------------------------------------------------------------------------- data Options = Options { useFullscreen :: Bool, windowWidth :: Int, windowHeight :: Int, bpp :: Maybe Int, refreshRate :: Maybe Int } startOpt :: Options startOpt = Options { useFullscreen = False, windowWidth = 800, windowHeight = 600, bpp = Nothing, refreshRate = Nothing } options :: [OptDescr (Options -> IO Options)] options = [ Option ['f'] ["fullscreen"] (NoArg (\opt -> return opt { useFullscreen = True })) "use fullscreen mode if possible", Option ['w'] ["width"] (ReqArg (\arg opt -> do w <- readInt "WIDTH" arg return opt { windowWidth = w }) "WIDTH") "use window width WIDTH", Option ['h'] ["height"] (ReqArg (\arg opt -> do h <- readInt "HEIGHT" arg return opt { windowHeight = h }) "HEIGHT") "use window height HEIGHT", Option ['b'] ["bpp"] (ReqArg (\arg opt -> do b <- readInt "BPP" arg return opt { bpp = Just b }) "BPP") "use BPP bits per plane (ignored in windowed mode)", Option ['r'] ["refresh-rate"] (ReqArg (\arg opt -> do r <- readInt "HZ" arg return opt { refreshRate = Just r }) "HZ") "use refresh rate HZ (ignored in windowed mode)", Option ['?'] ["help"] (NoArg (\_ -> do usage >>= putStr safeExitWith ExitSuccess)) "show help" ] readInt :: String -> String -> IO Int readInt name arg = case reads arg of ((x,[]) : _) -> return x _ -> dieWith ["Can't parse " ++ name ++ " argument '" ++ arg ++ "'\n"] usage :: IO String usage = do progName <- getProgName return $ usageInfo ("Usage: " ++ progName ++ " [OPTION...]") options parseOptions :: [String] -> IO Options parseOptions args = do let (optsActions, nonOptions, errs) = getOpt Permute options args unless (null nonOptions && null errs) (dieWith errs) foldl (>>=) (return startOpt) optsActions dieWith :: [String] -> IO a dieWith errs = do u <- usage mapM_ (hPutStr stderr) (errs ++ [u]) safeExitWith (ExitFailure 1) -------------------------------------------------------------------------------- -- Handle mouse and keyboard events. For this simple demo, just exit when -- ESCAPE is pressed. -------------------------------------------------------------------------------- keyboardMouseHandler :: KeyboardMouseCallback keyboardMouseHandler (Char '\27') Down _ _ = safeExitWith ExitSuccess keyboardMouseHandler _ _ _ _ = return () safeExitWith :: ExitCode -> IO a safeExitWith code = do gma <- get gameModeActive when gma leaveGameMode exitWith code -------------------------------------------------------------------------------- -- Do one time setup, i.e. set the clear color. -------------------------------------------------------------------------------- initialize :: IO () initialize = clearColor $= Color4 0 0 0 0 -------------------------------------------------------------------------------- -- Reset the viewport for window changes. -------------------------------------------------------------------------------- setupProjection :: ReshapeCallback setupProjection (Size width height) = do -- don't want a divide by zero let h = max 1 height -- reset the viewport to new dimensions viewport $= (Position 0 0, Size width h) -- set projection matrix as the current matrix matrixMode $= Projection -- reset projection matrix loadIdentity -- calculate aspect ratio of window perspective 52 (fromIntegral width / fromIntegral h) 1 1000 -- set modelview matrix matrixMode $= Modelview 0 -- reset modelview matrix loadIdentity -------------------------------------------------------------------------------- -- Clear and redraw the scene. -------------------------------------------------------------------------------- render :: DisplayCallback render = do -- clear screen and depth buffer clear [ ColorBuffer, DepthBuffer ] loadIdentity lookAt (Vertex3 0 10 0.1) (Vertex3 0 0 0) (Vector3 0 1 0) -- function to draw a series of lines of increasing width let drawLines x = zipWithM_ (\lw line -> do -- set the line width lineWidth $= lw -- draw the line renderPrimitive Lines $ do vertex (Vertex3 x 0 (line - 3)) vertex (Vertex3 (x + 4) 0 (line - 3))) [ 0.5 .. ] [ 0, 0.5 .. 6.5 :: GLfloat ] -- draw a series of lines of increasing width without stippling drawLines (-5) -- set the stipple pattern, 0xAAAA = 1010 1010 1010 1010 lineStipple $= Just (2, 0xAAAA) -- draw a series of lines of increasing width with stippling drawLines 1 -- disable stippling lineStipple $= Nothing GLUT-2.7.0.16/examples/BOGLGP/Chapter02/OpenGLApplication.hs0000644000000000000000000002017013255126367021104 0ustar0000000000000000{- OpenGLApplication.hs (adapted from OpenGLApplication which is (c) 2004 Astle/Hawkins) Copyright (c) Sven Panne 2004-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE -} import Control.Monad ( when, unless ) import Data.IORef ( IORef, newIORef ) import Data.Maybe ( isJust ) import Graphics.UI.GLUT hiding ( initialize ) import System.Console.GetOpt import System.Environment ( getProgName ) import System.Exit ( exitWith, ExitCode(..) ) import System.IO ( hPutStr, stderr ) -------------------------------------------------------------------------------- -- Setup GLUT and OpenGL, drop into the event loop. -------------------------------------------------------------------------------- main :: IO () main = do -- Setup the basic GLUT stuff (_, args) <- getArgsAndInitialize opts <- parseOptions args initialDisplayMode $= [ DoubleBuffered, RGBMode, WithDepthBuffer ] (if useFullscreen opts then fullscreenMode else windowedMode) opts state <- initialize -- Register the event callback functions displayCallback $= do render state; swapBuffers reshapeCallback $= Just setupProjection keyboardMouseCallback $= Just keyboardMouseHandler idleCallback $= Just (do prepare state; postRedisplay Nothing) -- At this point, control is relinquished to the GLUT event handler. -- Control is returned as events occur, via the callback functions. mainLoop fullscreenMode :: Options -> IO () fullscreenMode opts = do let addCapability c = maybe id (\x -> (Where' c IsEqualTo x :)) gameModeCapabilities $= (addCapability GameModeWidth (Just (windowWidth opts)) . addCapability GameModeHeight (Just (windowHeight opts)) . addCapability GameModeBitsPerPlane (bpp opts) . addCapability GameModeRefreshRate (refreshRate opts)) [] _ <- enterGameMode maybeWin <- get currentWindow if isJust maybeWin then cursor $= None else do hPutStr stderr "Could not enter fullscreen mode, using windowed mode\n" windowedMode (opts { useFullscreen = False } ) windowedMode :: Options -> IO () windowedMode opts = do initialWindowSize $= Size (fromIntegral (windowWidth opts)) (fromIntegral (windowHeight opts)) _ <- createWindow "BOGLGP - Chapter 2 - OpenGL Application" return () -------------------------------------------------------------------------------- -- Option handling -------------------------------------------------------------------------------- data Options = Options { useFullscreen :: Bool, windowWidth :: Int, windowHeight :: Int, bpp :: Maybe Int, refreshRate :: Maybe Int } startOpt :: Options startOpt = Options { useFullscreen = False, windowWidth = 800, windowHeight = 600, bpp = Nothing, refreshRate = Nothing } options :: [OptDescr (Options -> IO Options)] options = [ Option ['f'] ["fullscreen"] (NoArg (\opt -> return opt { useFullscreen = True })) "use fullscreen mode if possible", Option ['w'] ["width"] (ReqArg (\arg opt -> do w <- readInt "WIDTH" arg return opt { windowWidth = w }) "WIDTH") "use window width WIDTH", Option ['h'] ["height"] (ReqArg (\arg opt -> do h <- readInt "HEIGHT" arg return opt { windowHeight = h }) "HEIGHT") "use window height HEIGHT", Option ['b'] ["bpp"] (ReqArg (\arg opt -> do b <- readInt "BPP" arg return opt { bpp = Just b }) "BPP") "use BPP bits per plane (ignored in windowed mode)", Option ['r'] ["refresh-rate"] (ReqArg (\arg opt -> do r <- readInt "HZ" arg return opt { refreshRate = Just r }) "HZ") "use refresh rate HZ (ignored in windowed mode)", Option ['?'] ["help"] (NoArg (\_ -> do usage >>= putStr safeExitWith ExitSuccess)) "show help" ] readInt :: String -> String -> IO Int readInt name arg = case reads arg of ((x,[]) : _) -> return x _ -> dieWith ["Can't parse " ++ name ++ " argument '" ++ arg ++ "'\n"] usage :: IO String usage = do progName <- getProgName return $ usageInfo ("Usage: " ++ progName ++ " [OPTION...]") options parseOptions :: [String] -> IO Options parseOptions args = do let (optsActions, nonOptions, errs) = getOpt Permute options args unless (null nonOptions && null errs) (dieWith errs) foldl (>>=) (return startOpt) optsActions dieWith :: [String] -> IO a dieWith errs = do u <- usage mapM_ (hPutStr stderr) (errs ++ [u]) safeExitWith (ExitFailure 1) -------------------------------------------------------------------------------- -- Handle mouse and keyboard events. For this simple demo, just exit when -- ESCAPE is pressed. -------------------------------------------------------------------------------- keyboardMouseHandler :: KeyboardMouseCallback keyboardMouseHandler (Char '\27') Down _ _ = safeExitWith ExitSuccess keyboardMouseHandler _ _ _ _ = return () safeExitWith :: ExitCode -> IO a safeExitWith code = do gma <- get gameModeActive when gma leaveGameMode exitWith code -------------------------------------------------------------------------------- -- The globale state, which is only the current angle in this simple demo. -- We don't need the window dimensions here, they are not used and would -- be easily available via GLUT anyway. -------------------------------------------------------------------------------- data State = State { angle :: IORef GLfloat } makeState :: IO State makeState = do a <- newIORef 0 return $ State { angle = a } -------------------------------------------------------------------------------- -- Do one time setup, i.e. set the clear color and create the global state. -------------------------------------------------------------------------------- initialize :: IO State initialize = do -- clear to black background clearColor $= Color4 0 0 0 0 makeState -------------------------------------------------------------------------------- -- Reset the viewport for window changes. -------------------------------------------------------------------------------- setupProjection :: ReshapeCallback setupProjection (Size width height) = do -- don't want a divide by zero let h = max 1 height -- reset the viewport to new dimensions viewport $= (Position 0 0, Size width h) -- set projection matrix as the current matrix matrixMode $= Projection -- reset projection matrix loadIdentity -- calculate aspect ratio of window perspective 52 (fromIntegral width / fromIntegral h) 1 1000 -- set modelview matrix matrixMode $= Modelview 0 -- reset modelview matrix loadIdentity -------------------------------------------------------------------------------- -- Perform any data-specific updates for a frame. Here we only increment the -- angle for the rotation of the triangle. -------------------------------------------------------------------------------- prepare :: State -> IdleCallback prepare state = do angle state $~ (+ 0.1) -------------------------------------------------------------------------------- -- Clear and redraw the scene. -------------------------------------------------------------------------------- render :: State -> DisplayCallback render state = do -- clear screen and depth buffer clear [ ColorBuffer, DepthBuffer ] loadIdentity -- resolve overloading, not needed in "real" programs let translate3f = translate :: Vector3 GLfloat -> IO () color3f = color :: Color3 GLfloat -> IO () vertex3f = vertex :: Vertex3 GLfloat -> IO () -- move back 5 units and rotate about all 3 axes translate3f (Vector3 0 0 (-5)) a <- get (angle state) rotate a (Vector3 1 0 0) rotate a (Vector3 0 1 0) rotate a (Vector3 0 0 1) -- lime greenish color color3f (Color3 0.7 1 0.3) -- draw the triangle such that the rotation point is in the center renderPrimitive Triangles $ do vertex3f (Vertex3 1 (-1) 0) vertex3f (Vertex3 (-1) (-1) 0) vertex3f (Vertex3 0 1 0) GLUT-2.7.0.16/examples/BOGLGP/Chapter02/OnYourOwn1.hs0000644000000000000000000002013613255126367017576 0ustar0000000000000000{- OnYourOwn1.hs (adapted from OpenGLApplication which is (c) 2004 Astle/Hawkins) Copyright (c) Sven Panne 2004-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE -} import Control.Monad ( when, unless ) import Data.IORef ( IORef, newIORef ) import Data.Maybe ( isJust ) import Graphics.UI.GLUT hiding ( initialize ) import System.Console.GetOpt import System.Environment ( getProgName ) import System.Exit ( exitWith, ExitCode(..) ) import System.IO ( hPutStr, stderr ) -------------------------------------------------------------------------------- -- Setup GLUT and OpenGL, drop into the event loop. -------------------------------------------------------------------------------- main :: IO () main = do -- Setup the basic GLUT stuff (_, args) <- getArgsAndInitialize opts <- parseOptions args initialDisplayMode $= [ DoubleBuffered, RGBMode, WithDepthBuffer ] (if useFullscreen opts then fullscreenMode else windowedMode) opts state <- initialize -- Register the event callback functions displayCallback $= do render state; swapBuffers reshapeCallback $= Just setupProjection keyboardMouseCallback $= Just keyboardMouseHandler idleCallback $= Just (do prepare state; postRedisplay Nothing) -- At this point, control is relinquished to the GLUT event handler. -- Control is returned as events occur, via the callback functions. mainLoop fullscreenMode :: Options -> IO () fullscreenMode opts = do let addCapability c = maybe id (\x -> (Where' c IsEqualTo x :)) gameModeCapabilities $= (addCapability GameModeWidth (Just (windowWidth opts)) . addCapability GameModeHeight (Just (windowHeight opts)) . addCapability GameModeBitsPerPlane (bpp opts) . addCapability GameModeRefreshRate (refreshRate opts)) [] _ <- enterGameMode maybeWin <- get currentWindow if isJust maybeWin then cursor $= None else do hPutStr stderr "Could not enter fullscreen mode, using windowed mode\n" windowedMode (opts { useFullscreen = False } ) windowedMode :: Options -> IO () windowedMode opts = do initialWindowSize $= Size (fromIntegral (windowWidth opts)) (fromIntegral (windowHeight opts)) _ <- createWindow "BOGLGP - Chapter 2 - On Your Own 1" return () -------------------------------------------------------------------------------- -- Option handling -------------------------------------------------------------------------------- data Options = Options { useFullscreen :: Bool, windowWidth :: Int, windowHeight :: Int, bpp :: Maybe Int, refreshRate :: Maybe Int } startOpt :: Options startOpt = Options { useFullscreen = False, windowWidth = 800, windowHeight = 600, bpp = Nothing, refreshRate = Nothing } options :: [OptDescr (Options -> IO Options)] options = [ Option ['f'] ["fullscreen"] (NoArg (\opt -> return opt { useFullscreen = True })) "use fullscreen mode if possible", Option ['w'] ["width"] (ReqArg (\arg opt -> do w <- readInt "WIDTH" arg return opt { windowWidth = w }) "WIDTH") "use window width WIDTH", Option ['h'] ["height"] (ReqArg (\arg opt -> do h <- readInt "HEIGHT" arg return opt { windowHeight = h }) "HEIGHT") "use window height HEIGHT", Option ['b'] ["bpp"] (ReqArg (\arg opt -> do b <- readInt "BPP" arg return opt { bpp = Just b }) "BPP") "use BPP bits per plane (ignored in windowed mode)", Option ['r'] ["refresh-rate"] (ReqArg (\arg opt -> do r <- readInt "HZ" arg return opt { refreshRate = Just r }) "HZ") "use refresh rate HZ (ignored in windowed mode)", Option ['?'] ["help"] (NoArg (\_ -> do usage >>= putStr safeExitWith ExitSuccess)) "show help" ] readInt :: String -> String -> IO Int readInt name arg = case reads arg of ((x,[]) : _) -> return x _ -> dieWith ["Can't parse " ++ name ++ " argument '" ++ arg ++ "'\n"] usage :: IO String usage = do progName <- getProgName return $ usageInfo ("Usage: " ++ progName ++ " [OPTION...]") options parseOptions :: [String] -> IO Options parseOptions args = do let (optsActions, nonOptions, errs) = getOpt Permute options args unless (null nonOptions && null errs) (dieWith errs) foldl (>>=) (return startOpt) optsActions dieWith :: [String] -> IO a dieWith errs = do u <- usage mapM_ (hPutStr stderr) (errs ++ [u]) safeExitWith (ExitFailure 1) -------------------------------------------------------------------------------- -- Handle mouse and keyboard events. For this simple demo, just exit when -- ESCAPE is pressed. -------------------------------------------------------------------------------- keyboardMouseHandler :: KeyboardMouseCallback keyboardMouseHandler (Char '\27') Down _ _ = safeExitWith ExitSuccess keyboardMouseHandler _ _ _ _ = return () safeExitWith :: ExitCode -> IO a safeExitWith code = do gma <- get gameModeActive when gma leaveGameMode exitWith code -------------------------------------------------------------------------------- -- The globale state, which is only the current angle in this simple demo. -- We don't need the window dimensions here, they are not used and would -- be easily available via GLUT anyway. -------------------------------------------------------------------------------- data State = State { angle :: IORef GLfloat } makeState :: IO State makeState = do a <- newIORef 0 return $ State { angle = a } -------------------------------------------------------------------------------- -- Do one time setup, i.e. set the clear color and create the global state. -------------------------------------------------------------------------------- initialize :: IO State initialize = do -- clear to white background clearColor $= Color4 1 1 1 0 makeState -------------------------------------------------------------------------------- -- Reset the viewport for window changes. -------------------------------------------------------------------------------- setupProjection :: ReshapeCallback setupProjection (Size width height) = do -- don't want a divide by zero let h = max 1 height -- reset the viewport to new dimensions viewport $= (Position 0 0, Size width h) -- set projection matrix as the current matrix matrixMode $= Projection -- reset projection matrix loadIdentity -- calculate aspect ratio of window perspective 52 (fromIntegral width / fromIntegral h) 1 1000 -- set modelview matrix matrixMode $= Modelview 0 -- reset modelview matrix loadIdentity -------------------------------------------------------------------------------- -- Perform any data-specific updates for a frame. Here we only increment the -- angle for the rotation of the triangle. -------------------------------------------------------------------------------- prepare :: State -> IdleCallback prepare state = do angle state $~ (+ 0.1) -------------------------------------------------------------------------------- -- Clear and redraw the scene. -------------------------------------------------------------------------------- render :: State -> DisplayCallback render state = do -- clear screen and depth buffer clear [ ColorBuffer, DepthBuffer ] loadIdentity -- resolve overloading, not needed in "real" programs let translate3f = translate :: Vector3 GLfloat -> IO () color3f = color :: Color3 GLfloat -> IO () vertex3f = vertex :: Vertex3 GLfloat -> IO () -- move back 5 units and rotate about all 3 axes translate3f (Vector3 0 0 (-5)) a <- get (angle state) rotate a (Vector3 1 0 0) rotate a (Vector3 0 1 0) rotate a (Vector3 0 0 1) -- red color color3f (Color3 1 0 0) -- draw the triangle such that the rotation point is in the center renderPrimitive Triangles $ do vertex3f (Vertex3 1 (-1) 0) vertex3f (Vertex3 (-1) (-1) 0) vertex3f (Vertex3 0 1 0) GLUT-2.7.0.16/examples/BOGLGP/Chapter01/Simple.hs0000644000000000000000000000777613255126367017045 0ustar0000000000000000{- Simple.hs (adapted from Simple.cpp which is (c) 2004 Astle/Hawkins) Copyright (c) Sven Panne 2004-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE -} import Control.Monad ( unless ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT hiding ( initialize ) -------------------------------------------------------------------------------- -- Setup GLUT and OpenGL, drop into the event loop. -------------------------------------------------------------------------------- main :: IO () main = do -- Setup the basic GLUT stuff _ <- getArgsAndInitialize initialDisplayMode $= [ DoubleBuffered, RGBMode, WithDepthBuffer ] -- Create the window initialWindowSize $= Size 1024 768 initialWindowPosition $= Position 100 150 _ <- createWindow "BOGLGP - Chapter 1 - Simple" initialize -- Register the event callback functions displayCallback $= display reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboardMouseHandler -- No need for an idle callback here, this would just hog the CPU -- without any visible effect -- At this point, control is relinquished to the GLUT event handler. -- Control is returned as events occur, via the callback functions. mainLoop -------------------------------------------------------------------------------- -- One time setup, including creating menus, creating a light, setting the -- shading mode and clear color, and loading textures. -------------------------------------------------------------------------------- initialize :: IO () initialize = do -- set up the only meny attachMenu RightButton (Menu [MenuEntry "Exit" (exitWith ExitSuccess)]) depthFunc $= Just Less -------------------------------------------------------------------------------- -- Handle mouse and keyboard events. For this simple demo, just exit on a -- left click or when q is pressed. -------------------------------------------------------------------------------- keyboardMouseHandler :: KeyboardMouseCallback keyboardMouseHandler (MouseButton LeftButton)_ _ _ = exitWith ExitSuccess keyboardMouseHandler (Char 'q') _ _ _ = exitWith ExitSuccess keyboardMouseHandler _ _ _ _ = postRedisplay Nothing -------------------------------------------------------------------------------- -- Reset the viewport for window changes. -------------------------------------------------------------------------------- reshape :: ReshapeCallback reshape size@(Size width height) = unless (height == 0) $ do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 90 (fromIntegral width / fromIntegral height) 1 100 matrixMode $= Modelview 0 -------------------------------------------------------------------------------- -- Clear and redraw the scene. -------------------------------------------------------------------------------- display :: DisplayCallback display = do -- set up the camera loadIdentity lookAt (Vertex3 0 1 6) (Vertex3 0 0 0) (Vector3 0 1 0) -- clear the screen clear [ ColorBuffer, DepthBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () vertex3f = vertex :: Vertex3 GLfloat -> IO () -- draw a triangle renderPrimitive Triangles $ do color3f (Color3 1 0 0) vertex3f (Vertex3 2 2.5 (-1)) color3f (Color3 0 1 0) vertex3f (Vertex3 (-3.5) (-2.5) (-1)) color3f (Color3 0 0 1) vertex3f (Vertex3 2 (-4) 0) -- draw a polygon renderPrimitive Polygon $ do color3f (Color3 1 1 1) vertex3f (Vertex3 (-1) 2 0) color3f (Color3 1 1 0) vertex3f (Vertex3 (-3) (-0.5) 0) color3f (Color3 0 1 1) vertex3f (Vertex3 (-1.5) (-3) 0) color3f (Color3 0 0 0) vertex3f (Vertex3 1 (-2) 0) color3f (Color3 1 0 1) vertex3f (Vertex3 1 1 0) -- draw everything and swap the display buffer swapBuffers GLUT-2.7.0.16/examples/BOGLGP/Chapter01/OnYourOwn1.hs0000644000000000000000000001001113255126367017564 0ustar0000000000000000{- OnYourOwn1.hs (adapted from Simple.cpp which is (c) 2004 Astle/Hawkins) Copyright (c) Sven Panne 2004-2018 This file is part of HOpenGL and distributed under a BSD-style license See the file libraries/GLUT/LICENSE -} import Control.Monad ( unless ) import System.Exit ( exitWith, ExitCode(ExitSuccess) ) import Graphics.UI.GLUT hiding ( initialize ) -------------------------------------------------------------------------------- -- Setup GLUT and OpenGL, drop into the event loop. -------------------------------------------------------------------------------- main :: IO () main = do -- Setup the basic GLUT stuff _ <- getArgsAndInitialize initialDisplayMode $= [ DoubleBuffered, RGBMode, WithDepthBuffer ] -- Create the window initialWindowSize $= Size 1024 768 initialWindowPosition $= Position 100 150 _ <- createWindow "BOGLGP - Chapter 1 - On Your Own 1" initialize -- Register the event callback functions displayCallback $= display reshapeCallback $= Just reshape keyboardMouseCallback $= Just keyboardMouseHandler -- No need for an idle callback here, this would just hog the CPU -- without any visible effect -- At this point, control is relinquished to the GLUT event handler. -- Control is returned as events occur, via the callback functions. mainLoop -------------------------------------------------------------------------------- -- One time setup, including creating menus, creating a light, setting the -- shading mode and clear color, and loading textures. -------------------------------------------------------------------------------- initialize :: IO () initialize = do -- set up the only meny attachMenu RightButton (Menu [MenuEntry "Exit" (exitWith ExitSuccess)]) depthFunc $= Just Less -------------------------------------------------------------------------------- -- Handle mouse and keyboard events. For this simple demo, just exit on a -- left click or when q is pressed. -------------------------------------------------------------------------------- keyboardMouseHandler :: KeyboardMouseCallback keyboardMouseHandler (MouseButton LeftButton)_ _ _ = exitWith ExitSuccess keyboardMouseHandler (Char 'q') _ _ _ = exitWith ExitSuccess keyboardMouseHandler _ _ _ _ = postRedisplay Nothing -------------------------------------------------------------------------------- -- Reset the viewport for window changes. -------------------------------------------------------------------------------- reshape :: ReshapeCallback reshape size@(Size width height) = unless (height == 0) $ do viewport $= (Position 0 0, size) matrixMode $= Projection loadIdentity perspective 90 (fromIntegral width / fromIntegral height) 1 100 matrixMode $= Modelview 0 -------------------------------------------------------------------------------- -- Clear and redraw the scene. -------------------------------------------------------------------------------- display :: DisplayCallback display = do -- set up the camera loadIdentity lookAt (Vertex3 0 1 6) (Vertex3 0 0 0) (Vector3 0 1 0) -- clear the screen clear [ ColorBuffer, DepthBuffer ] -- resolve overloading, not needed in "real" programs let color3f = color :: Color3 GLfloat -> IO () vertex3f = vertex :: Vertex3 GLfloat -> IO () -- draw a triangle renderPrimitive Triangles $ do color3f (Color3 1 0 0) vertex3f (Vertex3 2 2.5 (-1)) color3f (Color3 1 0 0) vertex3f (Vertex3 (-3.5) (-2.5) (-1)) color3f (Color3 1 0 0) vertex3f (Vertex3 2 (-4) 0) -- draw a polygon renderPrimitive Polygon $ do color3f (Color3 0 0 1) vertex3f (Vertex3 (-1) 2 0) color3f (Color3 0 0 1) vertex3f (Vertex3 (-3) (-0.5) 0) color3f (Color3 0 0 1) vertex3f (Vertex3 (-1.5) (-3) 0) color3f (Color3 0 0 1) vertex3f (Vertex3 1 (-2) 0) color3f (Color3 0 0 1) vertex3f (Vertex3 1 1 0) -- draw everything and swap the display buffer swapBuffers GLUT-2.7.0.16/LICENSE0000644000000000000000000000272213255126367011730 0ustar0000000000000000Copyright (c) 2002-2018, Sven Panne All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. GLUT-2.7.0.16/Setup.hs0000644000000000000000000000005612604702100012333 0ustar0000000000000000import Distribution.Simple main = defaultMain GLUT-2.7.0.16/GLUT.cabal0000644000000000000000000005676614001236012012456 0ustar0000000000000000name: GLUT version: 2.7.0.16 synopsis: A binding for the OpenGL Utility Toolkit description: A Haskell binding for the OpenGL Utility Toolkit, a window system independent toolkit for writing OpenGL programs. For more information about the C library on which this binding is based, please see: . homepage: http://www.haskell.org/haskellwiki/Opengl bug-reports: https://github.com/haskell-opengl/GLUT/issues copyright: Copyright (C) 2002-2018 Sven Panne license: BSD3 license-file: LICENSE author: Sven Panne maintainer: Sven Panne , Jason Dagit category: Graphics build-type: Simple tested-with: GHC == 7.0.4 GHC == 7.2.2 GHC == 7.4.2 GHC == 7.6.3 GHC == 7.8.4 GHC == 7.10.3 GHC == 8.0.2 GHC == 8.2.2 GHC == 8.4.3 GHC == 8.6.5 GHC == 8.8.1 cabal-version: >= 1.10 extra-source-files: CHANGELOG.md README.md examples/00-README examples/BOGLGP/00-README examples/Misc/00-README examples/Misc/ColorTriangle/color_triangles.frag examples/Misc/ColorTriangle/color_triangles.vert examples/OrangeBook/00-README examples/OrangeBook/3Dlabs-License.txt examples/OrangeBook/ogl2brick/Brick.frag examples/OrangeBook/ogl2brick/Brick.vert examples/RedBook4/00-README examples/RedBook4/Data/leeds.bin examples/RedBook8/00-README examples/RedBook8/Chapter01/triangles.frag examples/RedBook8/Chapter01/triangles.vert flag UseNativeWindowsLibraries description: When compiling under Windows, use the native libraries instead of e.g. the ones coming with Cygwin or MSYS. flag BuildExamples description: Build various OpenGL/GLUT examples. default: False library exposed-modules: Graphics.UI.GLUT Graphics.UI.GLUT.Begin Graphics.UI.GLUT.Callbacks Graphics.UI.GLUT.Callbacks.Global Graphics.UI.GLUT.Callbacks.Window Graphics.UI.GLUT.Colormap Graphics.UI.GLUT.Debugging Graphics.UI.GLUT.DeviceControl Graphics.UI.GLUT.Fonts Graphics.UI.GLUT.GameMode Graphics.UI.GLUT.Initialization Graphics.UI.GLUT.Menu Graphics.UI.GLUT.Objects Graphics.UI.GLUT.Overlay Graphics.UI.GLUT.State Graphics.UI.GLUT.Window other-modules: Graphics.UI.GLUT.Callbacks.Registration Graphics.UI.GLUT.QueryUtils Graphics.UI.GLUT.Raw Graphics.UI.GLUT.Raw.Callbacks Graphics.UI.GLUT.Raw.Fonts Graphics.UI.GLUT.Raw.Functions Graphics.UI.GLUT.Raw.Tokens Graphics.UI.GLUT.Types c-sources: cbits/HsGLUT.c hs-source-dirs: src build-depends: base >= 3 && < 5, array >= 0.3 && < 0.6, containers >= 0.3 && < 0.7, transformers >= 0.2 && < 0.6, StateVar >= 1.1 && < 1.3, OpenGL >= 2.12 && < 3.1 default-language: Haskell2010 other-extensions: CPP ghc-options: -Wall if impl(ghc > 8) ghc-options: -Wcompat if os(windows) && flag(UseNativeWindowsLibraries) if arch(i386) cpp-options: "-DCALLCONV=stdcall" else cpp-options: "-DCALLCONV=ccall" cc-options: "-DUSE_GETPROCADDRESS" else cpp-options: "-DCALLCONV=ccall" cc-options: "-DUSE_DLSYM" executable BOGLGP01-OnYourOwn1 if !flag(BuildExamples) buildable: False main-is: OnYourOwn1.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/BOGLGP/Chapter01 default-language: Haskell2010 ghc-options: -Wall executable BOGLGP01-Simple if !flag(BuildExamples) buildable: False main-is: Simple.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/BOGLGP/Chapter01 default-language: Haskell2010 ghc-options: -Wall executable BOGLGP02-OnYourOwn1.hs if !flag(BuildExamples) buildable: False main-is: OnYourOwn1.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/BOGLGP/Chapter02 default-language: Haskell2010 ghc-options: -Wall executable BOGLGP02-OpenGLApplication.hs if !flag(BuildExamples) buildable: False main-is: OpenGLApplication.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/BOGLGP/Chapter02 default-language: Haskell2010 ghc-options: -Wall executable BOGLGP03-Lines if !flag(BuildExamples) buildable: False main-is: Lines.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/BOGLGP/Chapter03 default-language: Haskell2010 ghc-options: -Wall executable BOGLGP03-OnYourOwn1 if !flag(BuildExamples) buildable: False main-is: OnYourOwn1.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/BOGLGP/Chapter03 default-language: Haskell2010 ghc-options: -Wall executable BOGLGP03-Points if !flag(BuildExamples) buildable: False main-is: Points.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/BOGLGP/Chapter03 default-language: Haskell2010 ghc-options: -Wall executable BOGLGP03-Polygons if !flag(BuildExamples) buildable: False main-is: Polygons.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/BOGLGP/Chapter03 default-language: Haskell2010 ghc-options: -Wall executable BOGLGP03-TrianglesQuads if !flag(BuildExamples) buildable: False main-is: TrianglesQuads.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/BOGLGP/Chapter03 default-language: Haskell2010 ghc-options: -Wall executable Misc-ARBOcclude if !flag(BuildExamples) buildable: False main-is: ARBOcclude.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/Misc default-language: Haskell2010 ghc-options: -Wall executable Misc-ColorTriangle if !flag(BuildExamples) buildable: False main-is: ColorTriangle.hs other-modules: LoadShaders build-depends: base >= 3 && < 5, bytestring >= 0.9 && < 0.12, GLUT hs-source-dirs: examples/Misc/ColorTriangle, examples/RedBook8/common default-language: Haskell2010 ghc-options: -Wall executable Misc-ExtractContours if !flag(BuildExamples) buildable: False main-is: ExtractContours.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/Misc default-language: Haskell2010 ghc-options: -Wall executable Misc-Gears if !flag(BuildExamples) buildable: False main-is: Gears.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/Misc default-language: Haskell2010 ghc-options: -Wall executable Misc-Pitfall14 if !flag(BuildExamples) buildable: False main-is: Pitfall14.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/Misc default-language: Haskell2010 ghc-options: -Wall executable Misc-SmoothOpenGL3 if !flag(BuildExamples) buildable: False main-is: SmoothOpenGL3.hs build-depends: base >= 3 && < 5, bytestring >= 0.9 && < 0.12, OpenGLRaw >= 1.0 && < 3.4, GLUT hs-source-dirs: examples/Misc default-language: Haskell2010 ghc-options: -Wall executable Misc-Triangulate if !flag(BuildExamples) buildable: False main-is: Triangulate.hs build-depends: base >= 3 && < 5, random >= 1.0 && < 1.3, GLUT hs-source-dirs: examples/Misc default-language: Haskell2010 ghc-options: -Wall executable OrangeBook-Brick if !flag(BuildExamples) buildable: False main-is: Brick.hs build-depends: base >= 3 && < 5, bytestring >= 0.9 && < 0.12, GLUT hs-source-dirs: examples/OrangeBook/ogl2brick default-language: Haskell2010 ghc-options: -Wall executable RedBook4-AAIndex if !flag(BuildExamples) buildable: False main-is: AAIndex.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-AARGB if !flag(BuildExamples) buildable: False main-is: AARGB.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-AccAnti if !flag(BuildExamples) buildable: False main-is: AccAnti.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-AccPersp if !flag(BuildExamples) buildable: False main-is: AccPersp.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Alpha if !flag(BuildExamples) buildable: False main-is: Alpha.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Alpha3D if !flag(BuildExamples) buildable: False main-is: Alpha3D.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-BezCurve if !flag(BuildExamples) buildable: False main-is: BezCurve.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-BezMesh if !flag(BuildExamples) buildable: False main-is: BezMesh.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-BezSurf if !flag(BuildExamples) buildable: False main-is: BezSurf.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-BlendEqn if !flag(BuildExamples) buildable: False main-is: BlendEqn.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Checker if !flag(BuildExamples) buildable: False main-is: Checker.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Clip if !flag(BuildExamples) buildable: False main-is: Clip.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-ColorMat if !flag(BuildExamples) buildable: False main-is: ColorMat.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-ColorMatrix if !flag(BuildExamples) buildable: False main-is: ColorMatrix.hs other-modules: ReadImage build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-ColorTable if !flag(BuildExamples) buildable: False main-is: ColorTable.hs other-modules: ReadImage build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Combiner if !flag(BuildExamples) buildable: False main-is: Combiner.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Convolution if !flag(BuildExamples) buildable: False main-is: Convolution.hs other-modules: ReadImage build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Cube if !flag(BuildExamples) buildable: False main-is: Cube.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-CubeMap if !flag(BuildExamples) buildable: False main-is: CubeMap.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-DList if !flag(BuildExamples) buildable: False main-is: DList.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-DOF if !flag(BuildExamples) buildable: False main-is: DOF.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Double if !flag(BuildExamples) buildable: False main-is: Double.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-DrawF if !flag(BuildExamples) buildable: False main-is: DrawF.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Feedback if !flag(BuildExamples) buildable: False main-is: Feedback.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Fog if !flag(BuildExamples) buildable: False main-is: Fog.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-FogCoord if !flag(BuildExamples) buildable: False main-is: FogCoord.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-FogIndex if !flag(BuildExamples) buildable: False main-is: FogIndex.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Font if !flag(BuildExamples) buildable: False main-is: Font.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Hello if !flag(BuildExamples) buildable: False main-is: Hello.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Histogram if !flag(BuildExamples) buildable: False main-is: Histogram.hs other-modules: ReadImage build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Image if !flag(BuildExamples) buildable: False main-is: Image.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Light if !flag(BuildExamples) buildable: False main-is: Light.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Lines if !flag(BuildExamples) buildable: False main-is: Lines.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-MVArray if !flag(BuildExamples) buildable: False main-is: MVArray.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Material if !flag(BuildExamples) buildable: False main-is: Material.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Minmax if !flag(BuildExamples) buildable: False main-is: Minmax.hs other-modules: ReadImage build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Mipmap if !flag(BuildExamples) buildable: False main-is: Mipmap.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Model if !flag(BuildExamples) buildable: False main-is: Model.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-MoveLight if !flag(BuildExamples) buildable: False main-is: MoveLight.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-MultiTex if !flag(BuildExamples) buildable: False main-is: MultiTex.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Multisamp if !flag(BuildExamples) buildable: False main-is: Multisamp.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-PickDepth if !flag(BuildExamples) buildable: False main-is: PickDepth.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-PickSquare if !flag(BuildExamples) buildable: False main-is: PickSquare.hs build-depends: base >= 3 && < 5, array >= 0.1 && < 0.6, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Planet if !flag(BuildExamples) buildable: False main-is: Planet.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-PointP if !flag(BuildExamples) buildable: False main-is: PointP.hs build-depends: base >= 3 && < 5, random >= 1.0 && < 1.3, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-PolyOff if !flag(BuildExamples) buildable: False main-is: PolyOff.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Polys if !flag(BuildExamples) buildable: False main-is: Polys.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Quadric if !flag(BuildExamples) buildable: False main-is: Quadric.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Robot if !flag(BuildExamples) buildable: False main-is: Robot.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Scene if !flag(BuildExamples) buildable: False main-is: Scene.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Select if !flag(BuildExamples) buildable: False main-is: Select.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-ShadowMap if !flag(BuildExamples) buildable: False main-is: ShadowMap.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Smooth if !flag(BuildExamples) buildable: False main-is: Smooth.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Stencil if !flag(BuildExamples) buildable: False main-is: Stencil.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Stroke if !flag(BuildExamples) buildable: False main-is: Stroke.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-SurfPoints if !flag(BuildExamples) buildable: False main-is: SurfPoints.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Surface if !flag(BuildExamples) buildable: False main-is: Surface.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Teapots if !flag(BuildExamples) buildable: False main-is: Teapots.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Tess if !flag(BuildExamples) buildable: False main-is: Tess.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-TessWind if !flag(BuildExamples) buildable: False main-is: TessWind.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-TexBind if !flag(BuildExamples) buildable: False main-is: TexBind.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-TexGen if !flag(BuildExamples) buildable: False main-is: TexGen.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-TexProx if !flag(BuildExamples) buildable: False main-is: TexProx.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-TexSub if !flag(BuildExamples) buildable: False main-is: TexSub.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Texture3D if !flag(BuildExamples) buildable: False main-is: Texture3D.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-TextureSurf if !flag(BuildExamples) buildable: False main-is: TextureSurf.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Torus if !flag(BuildExamples) buildable: False main-is: Torus.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Trim if !flag(BuildExamples) buildable: False main-is: Trim.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-UnProject if !flag(BuildExamples) buildable: False main-is: UnProject.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-VArray if !flag(BuildExamples) buildable: False main-is: VArray.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook4-Wrap if !flag(BuildExamples) buildable: False main-is: Wrap.hs build-depends: base >= 3 && < 5, GLUT hs-source-dirs: examples/RedBook4 default-language: Haskell2010 ghc-options: -Wall executable RedBook8-Triangles if !flag(BuildExamples) buildable: False main-is: Triangles.hs other-modules: LoadShaders build-depends: base >= 3 && < 5, bytestring >= 0.9 && < 0.12, GLUT hs-source-dirs: examples/RedBook8/Chapter01, examples/RedBook8/common default-language: Haskell2010 ghc-options: -Wall source-repository head type: git location: https://github.com/haskell-opengl/GLUT.git GLUT-2.7.0.16/CHANGELOG.md0000644000000000000000000000261713766137116012540 0ustar00000000000000002.7.0.16 -------- * Relaxed upper version bounds for `random` and `bytestring`. 2.7.0.15 -------- * Fixed typo in documentation. * Relaxed upper version bound for `StateVar`. 2.7.0.14 -------- * Relaxed upper version bound for `containers`. 2.7.0.13 -------- * Relaxed upper version bound for `OpenGLRaw`. 2.7.0.12 -------- * Mac OS X: Make it possible to link against freeglut. 2.7.0.11 -------- * Linux: Try to load versioned GLUT library, too, because the unversioned one is often in *-dev packages only. 2.7.0.10 -------- * Mac OS X: Search public frameworks first, then system frameworks. 2.7.0.9 -------- * The GLUT package compiles without any additional library/framework now. * Windows: We search for a native freeglut DLL, a MinGW freeglut DLL and a classic GLUT DLL, in that order. 2.7.0.8 -------- * Relaxed upper version bound for `OpenGLRaw`. 2.7.0.7 ------- * Removed redundant constraints. 2.7.0.6 -------- * Relaxed upper version bound for `OpenGLRaw`. 2.7.0.5 -------- * Make things work with both old and new `OpenGLRaw`/`GLURaw` packages. * Build all examples via cabal, no need for `make` anymore. 2.7.0.4 -------- * Relaxed upper version bound for `transformers`. 2.7.0.3 -------- * Relaxed upper version bound for OpenGLRaw. * Added CHANGELOG.md to distribution. * Minor build/testing tweaks. 2.7.0.2 -------- * Fixed typo in shader file extension. * Relaxed bounds for OpenGL package. GLUT-2.7.0.16/README.md0000644000000000000000000000070512757244251012200 0ustar0000000000000000[![Hackage](https://img.shields.io/hackage/v/GLUT.svg)](https://hackage.haskell.org/package/GLUT) [![Stackage LTS](https://www.stackage.org/package/GLUT/badge/lts)](https://www.stackage.org/lts/package/GLUT) [![Stackage nightly](https://www.stackage.org/package/GLUT/badge/nightly)](https://www.stackage.org/nightly/package/GLUT) [![Build Status](https://img.shields.io/travis/haskell-opengl/GLUT/master.svg)](https://travis-ci.org/haskell-opengl/GLUT) GLUT-2.7.0.16/examples/00-README0000644000000000000000000000230612604702100013612 0ustar0000000000000000This directory contains OpenGL example programs from various sources: * BOGLP: Contains some examples from the book "Beginning OpenGL Game Programming", 2nd ed., by Benstead/Astle/Hawkins. * Misc: Contains a few random examples from e.g. the Mesa sources. * OrangeBook: Contains an example from the book "OpenGL Shading Language", 3rd ed, by Rost/Licea-Kane/Ginsburg/Kessenich/Lichtenbelt/Malan/Weiblen. * RedBook4: Contains all examples from the book "OpenGL Programming Guide: The Official Guide to Learning OpenGL, Version 1.4", 4th ed., by Shreiner/Woo/Neider/Davis. * RedBook8: Contains various examples from the book "OpenGL Programming Guide: The Official Guide to Learning OpenGL, Version 4.3", 8th ed., by Shreiner/Sellers/Kessenich/Licea-Kane. If you have 'make' and 'ghc' installed, you can just issue 'make' at any directory level to compile the examples. 'make clean' cleans up afterwards, and you can use '-j [N]' for parallel builds. Directly loading the examples into e.g. ghci is possible, too, just ':load' an example and run it via 'main'. For some examples, you might have to extend the search path like '-i../common', see the corresponding Makefile. GLUT-2.7.0.16/examples/BOGLGP/00-README0000644000000000000000000000017512604702100014566 0ustar0000000000000000This directory contains some examples from the book "Beginning OpenGL Game Programming", 2nd ed., by Benstead/Astle/Hawkins. GLUT-2.7.0.16/examples/Misc/00-README0000644000000000000000000000011212604702100014476 0ustar0000000000000000This directory contains a few random examples from e.g. the Mesa sources. GLUT-2.7.0.16/examples/Misc/ColorTriangle/color_triangles.frag0000644000000000000000000000012712604702100022202 0ustar0000000000000000#version 430 core in vec4 color; out vec4 fColor; void main() { fColor = color; } GLUT-2.7.0.16/examples/Misc/ColorTriangle/color_triangles.vert0000644000000000000000000000026012604702100022241 0ustar0000000000000000#version 430 core layout(location = 0) in vec4 vPosition; layout(location = 1) in vec4 vColor; out vec4 color; void main() { gl_Position = vPosition; color = vColor; } GLUT-2.7.0.16/examples/OrangeBook/00-README0000644000000000000000000000022512604702100015636 0ustar0000000000000000This directory contains an example from the book "OpenGL Shading Language", 3rd ed, by Rost/Licea-Kane/Ginsburg/Kessenich/Lichtenbelt/Malan/Weiblen. GLUT-2.7.0.16/examples/OrangeBook/3Dlabs-License.txt0000644000000000000000000000275612604702100020005 0ustar0000000000000000Copyright (C) 2002-2005 3Dlabs Inc. Ltd. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of 3Dlabs Inc. Ltd. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. GLUT-2.7.0.16/examples/OrangeBook/ogl2brick/Brick.frag0000644000000000000000000000141412604702100020313 0ustar0000000000000000// // Fragment shader for procedural bricks // // Authors: Dave Baldwin, Steve Koren, Randi Rost // based on a shader by Darwyn Peachey // // Copyright (c) 2002-2004 3Dlabs Inc. Ltd. // // See 3Dlabs-License.txt for license information // uniform vec3 BrickColor, MortarColor; uniform vec2 BrickSize; uniform vec2 BrickPct; varying vec2 MCposition; varying float LightIntensity; void main(void) { vec3 color; vec2 position, useBrick; position = MCposition / BrickSize; if (fract(position.y * 0.5) > 0.5) position.x += 0.5; position = fract(position); useBrick = step(position, BrickPct); color = mix(MortarColor, BrickColor, useBrick.x * useBrick.y); color *= LightIntensity; gl_FragColor = vec4 (color, 1.0); } GLUT-2.7.0.16/examples/OrangeBook/ogl2brick/Brick.vert0000644000000000000000000000213312604702100020353 0ustar0000000000000000// // Vertex shader for procedural bricks // // Authors: Dave Baldwin, Steve Koren, Randi Rost // based on a shader by Darwyn Peachey // // Copyright (c) 2002-2004 3Dlabs Inc. Ltd. // // See 3Dlabs-License.txt for license information // uniform vec3 LightPosition; const float SpecularContribution = 0.3; const float DiffuseContribution = 1.0 - SpecularContribution; varying float LightIntensity; varying vec2 MCposition; void main(void) { vec3 ecPosition = vec3 (gl_ModelViewMatrix * gl_Vertex); vec3 tnorm = normalize(gl_NormalMatrix * gl_Normal); vec3 lightVec = normalize(LightPosition - ecPosition); vec3 reflectVec = reflect(-lightVec, tnorm); vec3 viewVec = normalize(-ecPosition); float diffuse = max(dot(lightVec, tnorm), 0.0); float spec = 0.0; if (diffuse > 0.0) { spec = max(dot(reflectVec, viewVec), 0.0); spec = pow(spec, 16.0); } LightIntensity = DiffuseContribution * diffuse + SpecularContribution * spec; MCposition = gl_Vertex.xy; gl_Position = ftransform(); } GLUT-2.7.0.16/examples/RedBook4/00-README0000644000000000000000000001252512604702100015227 0ustar0000000000000000This file lists the programs that are referenced in the OpenGL Programming Guide, Fourth Edition, by chapter. For each program, the version of OpenGL that is required is listed with the program. Chapter 1: Introduction to OpenGL Hello.hs (1.0) Double.hs (1.0) Chapter 2: State Management and Drawing Geometric Objects Lines.hs (1.0) Polys.hs (1.0) VArray.hs (1.1) MVArray.hs (1.4) Chapter 3: Viewing Cube.hs (1.0) Model.hs (1.0) Clip.hs (1.0) Planet.hs (1.0) Robot.hs (1.0) UnProject.hs (1.1) Chapter 4: Color Smooth.hs (1.0) Chapter 5: Lighting Light.hs (1.0) MoveLight.hs (1.0) Material.hs (1.0) ColorMat.hs (1.1) Scene.hs (1.0) Chapter 6: Blending, Antialiasing, Fog, and Polygon Offset BlendEqn.hs (1.3 or ARB_imaging_subset) Alpha.hs (1.0) Alpha3D.hs (1.1) AARGB.hs (1.1) AAIndex.hs (1.1) Multisamp.hs (1.3) Fog.hs (1.0) FogIndex.hs (1.0) FogCoord.hs (1.4) PointP.hs (1.4) PolyOff.hs (1.1) Chapter 7: Display Lists Torus.hs (1.0) DList.hs (1.0) Stroke.hs (1.0) Chapter 8: Drawing Pixels, Bitmaps, Fonts, and Images DrawF.hs (1.0) Font.hs (1.0) Image.hs (1.1) ColorTable.hs (ARB_imaging_subset) Convolution.hs (ARB_imaging_subset) ColorMatrix.hs (ARB_imaging_subset) Histogram.hs (ARB_imaging_subset) Minmax.hs (ARB_imaging_subset) Chapter 9: Texture Mapping Checker.hs (1.0) TexSub.hs (1.1) Texture3D.hs (1.2) Mipmap.hs (1.0) TexBind.hs (1.1) TexGen.hs (1.1) CubeMap.hs (1.3) MultiTex.hs (1.3 or ARB_multitexture) Combiner.hs (1.3) ShadowMap.hs (1.4) Wrap.hs (1.0) TexProx.hs (1.1) Chapter 10: The Framebuffer Stencil.hs (1.0) AccPersp.hs (1.0) AccAnti.hs (1.0) DOF.hs (1.0) Chapter 11: Tessellators and Quadrics Tess.hs (1.1) TessWind.hs (1.1) Quadric.hs (1.1) Chapter 12: Evaluators and NURBS BezCurve.hs (1.1) BezSurf.hs (1.1) BezMesh.hs (1.1) TextureSurf.hs (1.1) Surface.hs (1.1) SurfPoints.hs (1.2) Trim.hs (1.1) Chapter 13: Selection and Feedback Select.hs (1.1) PickSquare.hs (1.0) PickDepth.hs (1.0) Feedback.hs (1.0) Chapter 14: Now That You Know Color Plates: Teapots.hs (1.1) Some remarks regarding the style of the programs: To ease comparisons, the Haskell programs in this directory try to stay as close to the original examples in C as possible. Consequently, they should not be considered as examples for the best way to implement things in Haskell. The Haskell OpenGL binding uses overloading quite extensively, which makes its use quite flexible, e.g.: class Vertex a where vertex :: a -> IO () vertexv :: Ptr a -> IO () This single class subsumes all 24 vertex specification calls in OpenGL's C binding, i.e. glVertex{234}{sifd}[v](), with the help of the following class and instances: class VertexComponent a -- an opaque class VertexComponent GLshort VertexComponent GLint VertexComponent GLfloat VertexComponent GLdouble VertexComponent a => Vertex (Vertex2 a) VertexComponent a => Vertex (Vertex3 a) VertexComponent a => Vertex (Vertex4 a) There is a small inconvenience with this when used in "toy" programs: Haskell's numeric literals are overloaded, too, so the programmer's help is needed to disambiguate the type of expressions like: vertex (Vertex3 0 0 1) Let's assume we mean the equivalent of glVertex3f() here. One can either use an explicitly typed helper function: let vertex3f = vertex :: Vertex3 GLfloat -> IO () in vertex3f (Vertex3 0 0 1) This comes in handy when there are a lot of uses of vertex3f. An alternative is to use a type annotation for the literal: vertex (Vertex3 0 0 (1 :: GLfloat)) or a type annotation for the vertex: vertex (Vertex3 0 0 1 :: Vertex3 GLfloat) This is largely a matter of taste and normally not a problem in "real" programs with type signatures for functions. Sometimes different callbacks need to share some state, which is done via global variables in the C examples. To achieve a unified presentation, all Haskell examples use a `State' type for this purpose, which collects the different parts of the global state, i.e. one or more IORefs. There are alternatives for modeling this, which should be considered in own programs, depending on the use cases: * Separate IORefs: This makes it explicit which parts of the program need which parts of the state. * A single IORef/MVar containing all the state: This enables one to change the whole state atomically, which is often quite handy in multithreaded programs. * A custom monad: This can hide all the state threading behind the scenes. GLUT-2.7.0.16/examples/RedBook4/Data/leeds.bin0000644000000000000000000257733512604702100016612 0ustar0000000000000000Wӓsmgbdoosjpp}ģƪŪ˫ɬ˯ʹͳ̸ϻѿ·ƺȻɼ˽ϽϾν̻ʾۿmZhk.`o.pp7_S'^g4LU.OZ2=H;B!\Z!dg+ELOR-__8]X%RQ)[JHNLN FN >O%NN&IP'`T+KM#FILN$FZ'^h.U[,O]-WU(GT*EY%Ca&7U2ZZ*AO%MM-CW-B].Bh:C\-=]%3O""@*F!.I!9K&CT+5M'6R+1]0Ej12W).P%(K#>V):Q.0O-&N!#F G%K)D*C&1H#W(>Q%D_.8_6Gb<;_4Hc7Lb4@c*;d/5a-=Z.<]2e2Cd/4R,b55]4Ee5Ks@Ik=NvAFeE[wLJh=?`54W2>`;EX:BdCA`>HeCCc>;X5>`@>V=HmC4Z75X6?XB=\?F_BTxRNjM:dGU}V`}SIlM9[@;^SKjXDlPJtPIrTFjO_}Y[zMe_aaoljl_e`o]kYhoqbeQq_On`Y|jT_KubBe`KjiaoXi^}r[|gXn_ogaxe{x{f]rgl]`dcdnhohlrnrfjkplx|zz}ǝƘ˜ƙŞáƥȧȦɢȢɪʫ̪˫ͬ˯ϮѮүҮҲկӰղӶֲִֶֶָطֶٸڹܹܻݽݽ׾ƹhzFhr.i}8rCp)ui+na)sn*hN"ed*_e*]^(`bed"jUoZ"po,lp*jm'nt.lk&bU_k"jr#c\ea$nl+b[(^a(h^&\SfT#`_#_V"XR$`Y$`P&_e1VX%HN#gW"W\$_K$LM$BK$MR&hp6[M#ZF"MLGO!PRGJ"ZW%P]*HK+ZV'UT!MC9E9G/?-@OG!?M$9L#?T0;NUU$LPIR&GX&HZ+GV&FHAO!9I"IN"8Q2Q!AG!IN+:A$2E 2EGM)7N!@J!DP'1H+EGR!CW"BZ-8S%Gc-\e2JQ$?[2A\,>[&K",DA_(9W$BK#>O$,K,K8P!;L#B\,CW":O%FZ%2E3C$90L!:W%>`&Fi*@]#:O:X$=V$>Y$NW'Zd)GW"DX"AO GE!KD IG8H6HV\!fh)]^%RV'?W,AS)]j3[h1GW'bg3K_+\Y+DS&KH i]&Sj*U` EC:T%@I FH 8DIP%OY"XW.NU$Wa'ae0`]*IS$H[)O\(Ug3OZ(K`'@S$AJ!mk*P_)D`+Ea,g{9Nh/E^#B_*Op?FY'Yr;`w7mCSj.ud]i6os=Vj5dm/PV \h3[p1Yf+I[+ag0kh6Za-ge)ox0|z5w0yp0ju9sg5mi3]j5dm*}u7|5ty6nv>ru@x=uB`}=ezyHou=`sAltC}t=}Cr|||:s>ir=_x;]s4k}?j|?Di~Bu|7}=wLPt~BwJ~G|JpJpBuFgFg|=vGzFi;e{6j|8wCj|5Qr;bB\tDxGnBh}>Zn+]n/b};Yw8Yvi?[r4]v3\k+h:bx7e~<]z9e;jA^y;g~?iz8b|9Zx?gBY{?Wp,Mi/LV&Id.To4Lh-f8k9_=_?Xr3?W%Xq:_x;Xs5Kp1_{hDVx<]v;f~AaFuJcF_BdBd}=d=dHjG`FZ~Bh;l@R|?hOeP|WPuHwKqLhNjCiAeMYI\AaMiQhT^JcOjS[E\HmHdPbHgN`HoLVxEVLaQXP_KlVjVjOw_pSgRWPeIgOeS|`aSz]eXu[}^yaiYmau^oZbX_\bY^`^UQ}L_Kl`}Zzd|dtZoWiOkTvWkTdNlTyer^oel\g}_vat`r_pRpWjPhRlTeRbYnPqal\tRp\pSu^gdaeed_SMrFeRk]nad`hbhay`oapcj]yjq\o^pil]rdulp`g[q]{\~fh^nlyi`flai`k\r`sdbVYbi\bbjZqj_ygerifa|`rZ\{hswkp|ttaefiryxw}kcbgicjwrmcvc~dydu_pderrzeye}gs_lyk}gnbqdsivhqgjbobk^h^_ZmVfֶkg8fj*ih!il0re1r`"fW^P"\SeW(li0ic%T\ X^_Z"ig(gW!hX*`V!\T[S fbaU OP[L!_WgbhV mg"dd+TTHGUS YK ]N#TR&bU#ib"IMTARG"RU)RI!JKR^4W_&OS#CO6J"TM67PK!BMUNQR%XP#PIEM?C><:B:C!@LBQRUDJAG?L0=-E39HP EO>N6J=F7H"E_/E[(VU)EQ >W(9NIL?K3J@S&2@!0C0E3C>I9IBT >D?N#G_3SS#L_ 8^';\7V;OCb(L_*>Z,:\';ZC^ RWAM;Y#@R$K]%E_#4O9OJ[>H?N@Z'Ib'EX&1O:P1N:Q2F3F1@OO!AKG];I4;?Q:J7R,I;L=W%HP)=+B1N8Q$OWA_%Se%Zf'HS/D6J4QA]TY SZ$MGKH GCJ8@<BBGLEJHNIPXNSU(EO%W[ix2@P!CT%EW(OT49D DLE@GGIUNa$>NHX)MP%HF@JO]!WW!\i@Xd:jj6pyR`g*]_*Xl2kl.fo0]k-ai1df-\a)U^*hl*Pb'Sa%I["Pk(J\"gv:dp4w|>p}5dy5ts-y}5yw/hm+ou0pn5yEv~<|?y/jx)xx/]s4Zse[%ca&ej,mr6qx?x}7~{:|?CyC}>>=jr*Zm&ew7lz:gy-kv-zDo{>py8uy;vv5{xAwDx~4~B}?sy5dj)\x5uz:^y?g?yDt:cxDq}Ar=_o,m|;j~?ev;g}=d;cA^{kBj?Wx3i8_;f4\{/i=dCm4c{+`|)^|1Yu5Vq)]z3\q.^w:av?`:[z4]r.Jd#Ud$[t6\t-Qr7Ii.Mf(Vu,Tv.Y}6YAOt:He+Yv1_y-_v,]u8Re$\}-Nm4Yx-_{2YwWx^00D7@+D:K!GV#EK%XPYU!DKJ\G_#@T%F\*0J7HRY!;\'4Y!Bi''B=H6Q%AM$$>-B@`'Ra'He*\d)7O?T(2K6K0J:_!;W :X3M6C-9CH@K>M2H)G,F,C-@%C-K;R9L,A-N9N8M:P/P5E,L.HCVHJBW;P!A[)C\$@_$Bb$:Y%Jl1FWBVB^%Id.2I1VHT9P;R2J)Dcx:cCiw2jn=h=v8\{;^x6Uu-Yu5a{9^x2Uv,Xw.Me!Un%[v2Rm0Ys7[p9cu5`s3e7`v&`u-`v,Zm&Ys0Oe*D]K]Yr$\i"v=bv:fx.[x2To(Mj!Xo#Wh#Ug"\w.d|6\s*`s,g|.Sl#Ut)\~-Xu/a~5g:d{1Vt,\u*Wy'Ss!Uv(Th%cy1On+Z{3Z|7Tu*Yp'Xu)e3]y*d6\y-Xt*Xu'Yv'_v)SlSr`}&d~:Yq)k@Yr+e9`w)_z.Yt-Xt/[v5Wp0^z]w/_x9\u2[r/[u-`~7f|:Qr];]"@\Fc'Qe#_o0Kc&Jh)H^Ib"@\Je'Rg&L_+G^%Mf)Le&Jh*Me%Nl-F\"A]$:HK]Le#Og'If'Mj*B^'Rk&Th+Tj)E`%Ec"?Z#5R5Q2RA^Cb%Ck,Ll*Gf(]s.Lj0Ul*Vm6\k%_v/]r'gy4Zu9Ni-Ps/_p(Qj(Qs0Rs/Bj%Ed!Pf'>V"?[#H\Gh&Jj'=Z"CXF\%C]%A]"So*AW!B^Fa$D_C^(;]+@U!B\"@X&3M=T;\%5S*?Z&vc֮dT*`],gm+mQ!eT)QU+ZL&\S"_`\h(di#YX`T#`^)]Q-]Y0eY+\W8C!YR#OS)LG!][&UL#ST"TLONLJRS!HLGI"WZ'QI"[])IQ%VT$Tb-[T!SK"\W(T[&HU,Pb2e[#AU&FSI]%`]'S[&NHLP-E[+Kb&=U#>N?KFD"SO3AJ'6F*OJ%RB6; )@L$@F 9=C668.@.D+A9MBO#AI$>K)EQ!4KS_'@Y 1N+T"AJ7B5@,A5G*A(D&A6L*D7I7H.I,F*J!?5K+@0L=\'GV#D[%La&BT0M?W$>[&1M!-M?W!C\'P$<[(:\%-G3N9KGOYBW!Id)BW%W]$]\"LU!Q^*BVBZ"E^%=Q>RRk-_h-Nd+Ak2Nm5Zr3Lg+Xm5_s;Qo,Ur1bv;mn/_l1eu@au^u/ds1[m*aBjv2Tg2[j3Yn4ew.[m*r|:br-kt,bk)Td(\n0]p2pt,dh&fo,pn.i}?r{Cmt<_p3ml-am.iz0Wi&be)js/{g'`](IG"LO#`k/d_'fh.lx>lz>nr;sv5cs3\j,mj*Wi,tu1pu0tq1`m+zA=t9l;k;iu4jp.js/ft2dv9`r0[h+[g,dg'Zv3br2Zq1ds8fvmC^i0^l2cl5_m7Vm8Ui*`v5]r6f|Am~;e}au4Si'Rj$Ws0Ur0Pe&]s+^r/YbSj%Ge%Lf On$Ln&[u.Jd(Wn/Qi)C\$Qf&Ei"Pp'Ts&Yo*Tr*Sp+Ql'Rq.Sp&Wq'\y0`~.Tv+^x)Wu*_v+`}.Zv)Ys)Yy,[x2bx<]m,]v4Zn/l}9d~EXw9[j&^w=_u9Sg-bu*av/]{6j}:bz:oBYq1Kh,Rk'G]N`Qc&\o.Xl/Vm.Xr2Zo-^y8Wn1Yw0]y9Le!Yr4Hj1Pp1\y4Lg+Ys/Pe*au[%@b/Jd.Wi*D^'Sj(Ri'He'Ke1G`1Ba&Ie)Pg(Wq:Qj,Nd*Md(Lp0Lj-Yo5Ql+Uu5N[%Rf,Yu:AZ(Li1Be1Tk-Mn3Wr4Ym)Vi2Jk-Ig/Db)>]*:U"J_F^%@X!@U >NC[ >S>THd)EZ)L_"M]H_(@YMd$Aa*D_)Jf(Qh*@_"Lc%Gh,H\$Zl/Ni1M^07L@a+Qj,Nh#Pk.\h-Vh&Id0J^/Ui-Si+@_)D_$Ge,DV$@R(Y$;Z'=P"Ac.>S%Dc.AZ,vlեWS+RO)QI"SJ#eL d_%]T[Q(`^&`e(`X#]R!WGSE$RO"ROHCUKSQ%RKRO$MN#DNAK RP*Pb&SP!\V)W_*T`/^c0\^#[\#?T#XT&Tb-aj/G`*MR$>V#]d2IY(AM :F/BJH=E:K@M@Q HT"=TJOAVDJ"CB$_\,OC36AAG-H?J;4:/A!>@HE&B6%&'2.A2N"+B/I$9O 8Q ?OGR!9F=M=I<>,C8R0GA`.M+L/P#?\)BW0.L=]$2P.J,G-L4K'B$>&C%@,G'D&G>Z(-N0M2L)K(I7Q*E3F5C(F-K3K-G)@%<!E,G'C*K#6P!1U,M0M?X!BZ$:W!Da#<^%;R2Z0O;O@Y)4Z#4W%,M9^$9K8O7KE\"C`'@R:U :S"6U$M]'Fa-F`%O_"CZ?U B[&^k,Ec)Lq3Ok,Rt1Qm-Jk.Jk2lH[t3Ml0Xv5]r)g4cy2Vs;cAbw.^w6o>]A]y3cq/]n)Jp.ao.`u6bx5dz2Wo/_i/as3Va,R_&Va/Lc2fw;Xj0Rj/iw5To)Xm)Xj,BW!?X$H]%Pg([h/[s8Qi+Zl)[o.Xk-Wn0Or1Od+Nd-Re,VX!I`$\u9gg)h{:Vn:Zs)Vj+as.\y9\t4hx5Rd(ar3]u:ny-m@rA_?^}9c}2ax0at0l|1hy8bw-ou/Si'Si$Se Xg#[m,`n0\i+^q/eq)^v6Se%Tk/im,Xj,Pd%aa'R[&gl2jd5e[)^j4X`3XX$yv4q3ou;g}=gx6er2\u5^q/gw5l{9\t2fu6qv2q~2{@r{3u9h{.dr-Vf'_o(kw;bs5cu1ax3ar/i;p~>m{6Zr.Yn,c9[s8[k2\i,\u6a{:Xv4y}=dy3as3Vm0by7e{9Tt2Wm0Xl.m{8^u2[x0^m.Ym.Oe(N_"Oj%J`$EY%D^$F`&Ne$Zs2Ys5Zq+`x-Ys-J`$X5R 5V8Q&M 2U?O@[ Df(Im.J`Rj$Rm.Zx/Ij%Op,Or5E\!Mj,Oo6Fe(\x/Rp0Qn0Qe%Kc)EY$Lc(K[$6U$Mh'EZEc'C[)?[(>a4:T#8Z#A]$B`&Ce*?_&CZ*,GBSF^D_!Rg'CW>R7Q+MLa"Gc(Le!@Y C`&Jf*Id,B\!Tl.Ld,Kd'Ql,Rh%Qk'Ji+Pl*D`-Ma*Qn9Rk/He,=M3I CX$Bf28U>[#Fc"=YCZA^!;Y BV3A0K6S!;T=T6S@N7R>QGd&Ca&;MBX>_,>T8S"2I7O5R;]#@R A`$9_ DV=S3K.E9\#AT$EZ Ke#@Z!?\H`"=Z'BY'<[(AV I`Kh(znҤSI,II&DD IMJUMHWEWT%]Z+P_*RH MMGH]LOSJZ*PS$\U)FN$DMGEIR"LPLI$]U(PV*OY"JV"LS VX$JR"AINNUNTX#ONNQ@H5CLE2O'FS!7C>M8H1I6@:NAR"EOGJBGSO=K0G?GMc.BG:FC@" ,%!5 BFFM#AC,9!:7T#F]#K^%3U 5T=U?Z 9S#5P!6\'0J>J@RC\#?W'5K0M!*J"+E3K(>(D1K(< .E,G-N+H*L+K,C+C(B0I-L1Q$';&;"?+F.I8LX"5T:Q/H'I?U2F1XB_"Gd&=W;X$-L/P!8V!3V=U:\&]s.ci+Re$^m"]t,ix's2w?wVB_$Gf#H^K`Oe(`q/`s)[z/a{2Wr._m$Yk%Mj"Ld"Xq/Zm(c}4\v0g3hz=j8Vi!Tj'Xo(Wr([r*]v+Xl+Kd"Ri!MbUp!YmRi!Ne Sk Sr4Xq)Nh"Kk(Sv9Vo)Rj B\BZRp4FbKd)BY@\!H`9K?WWm E`"AYMi'HbBYCbA]=YGf$@^F_Lh#Xf]s*ASJ_ Lb$M^ Lm)Ss*Uq%Rj"Xn&dy,`x,\s.e:a}/_o#Zt&Xn)f{2Tm'K\Qk&_y5[w9Mg"Xg&Rc]t0[p,Mi"Jg"Pi!H_#SiPl+E[UiESEOBL=W9S;TY @Y@]GX@W7O-G3F1L5QD_>S:O6RE_6WGc!Mk,B^$>T>LJ_"DZ*GQ!H[#Wi%Pg0B\*G]$E`0@W(>Q#C^$-D5LU%6O 6P?W.H6IC]7Q@KBTBK5I8P3L/H.G*?C\"5I,H"%<-B?Y5P *C4M.L4U ,GM5P:Y :[Db!Kc#F_({nϤOP.dS*SP%IN"SR"JHML#WR!YO-_X&ZU)PL"RD]`#AMRNIHNJ RO!XM#IP'HZ)O[)OV%G^'FS&HE FH62?KDQ%0K1IAA?8OK#IG!DKMM!.ABD5KRB9C >N#ULKQ":Y4V!BN FR!9C.7>C5?9K3F3C.>.E$<39+3IR3-C $1?FV&.I7X(@]!>["C\%?V&\&0S&CAU",D7O4S*I'H0X*E;X-5L;L4F*G1V'F*L.M.J>Y#5U (H%M.P ,L,K'D0Q 0P-B+F=W;T2R8[&@d)>Y"G_$<]1N;X D\$?R6R!AZ!ZA] Ka?]Ac"[!@_$AYGb"Hd(Ec$Fb EbH^ B^ D^ He"?`@^Bc%Pe"St8Pn,Fe%Ei*IaCZ Le!Li'H]>]/UHd"Hi)Lh"=[Ch"Gm#_u1Gl(Qi,H_ >X!7L:a&Xp+Gh.Kl)Vn(Ki+3L2J/M7X8[ D^DeIh&>\1Q;X/Q6L:MW^"=T:W#7])2^)/M1Z:^:[!Jk)Hl-<_,_(<_!Go2Gr,Rw5Su7_v2Zs2dy7`|B_}6f6bv-cy1Yx5Vt1Ce%Vr:Uw-Pm$Oi'Rk"Sq*Rk/Ng,Fi/Fd)Tu(Qq%Nq+Ni*\o1Wl/Wj(Um<[y1Uo+Sn)a}*`:]s0bBZx6]@Ps3Ik*Gn(Ij,WnVw6Ho5Po,W|:Xw0Uv-Yk'Um4Gc(Bd4Ib,Qo1Tq1Hh$Gi)Mm:Mn0C\(Mq;Jf-Lj-Um*T|6Wv.^w/_;bBSn,\w.Yy,Qu5ay-f{,Wh+f}7`8Ot5Sx5\~:`4j9\x0\r-dI_};`y7Ux4Wl._y5Wu-Qj'Yy:Ls0Hf-Qn-[{:Ut+Lm%Gi#Mj)De&Mh/Pj-9]!=[He Nn)g8Xt7Ni)Zq-\r1Wn'^}3l?d2^w_t)Xw4Hg+:U@`#Xt1Hk+Jf"D`Mh$Zz&e_.SA`$Gg(Je$9_D\Ci'@f#LgJa$Kc Gd+C\!IdHd!=ZD`=X:SH\ Le$Ri$C[A`@Y;W@^Qf!Nc Sl$Ip)Xt%Wo%Ee A`O^Ug*Nl0Hf&Ng(JbKe#Fd;[Nf!Mb#F`"C_Li(>bBh!Mm2J`"?`L`#C`@]#;W Gb%)J8\Ij$Wj'Ja"Ig1Ml-@`$Fj'Ge F]D]"Ga"6M9\%=]&0V?e ?b$.T9P;XD] Ge,Ca(BcGce@]Mp%Pg!`y.Tn(Bb&AW?Z8] 8b'>`#A]$Mi)>^!Jc&?\#0[$8c =a Bj Ca Fa%>c&9Z @g":Z 6X :[:X7P1P,M3R?\?^@`Gf!ASJ]!Mc(>^$;Z'CY )R&1Q;\#@Y"Ma*6X'5R7P;PA]*O0Q/Q&@Z"Gj06U'3R8X 'E1L,M,N4O2T 0U"=[8a 6_&-S+H4P+S (C8P0N"(L0W(P0P8U@N@_(=[$0V=\#Ab!:T,I6Y,M&H.O>b-U<["6O,H7U@^'9`'0T$?P=]!Nd&ogΜWV-LG$OGT@4AG=CG8JBB9LCC7I"RL QCHO#6J@LLH?DBEEH:JEK7P,J'BHX!BP>V#@R3Q:R%FT$;R*FY!=QBP#CJ6HOV)6N$<)9,H$D4G+<1L!;(@+B/H5U2N/H.I&>,L2P!\,E:V .S&,KDe)8^!2H>^>U:PHb#D_#D`&Ig,Je$Yk"So$Xo'I`Cc$Ng)Le*Qe*Mh-]u*Ti!Nf Yi%Te&[\%UY!KY Lg!Kd[w,]{1\t)^y3_w5^u1Qm/Nq-Nh"Wt.Nl*Uj#Vj+GY$Jb&^r)rq&Ud#Vj$`s*Ui)ew/Xh.^z3Z4]u'Rj'_5Qo+C_#[t4Wt0]zWH[&Zs'Sk$Og'Yl'Ti%Ph&N` D]EbOk"Db J]Zh"[j'Vk(O` Rf'Kk)[x.]p Xo'bt'Yj&G[Wm*Jf'Jl*@dJb Mi#G\AWIf Gf&Lp#Lg!WpAa CZI^B` AV:Y Gb"Tm%Mj$PjRr'[m)Lh'Ok)Sg(Ng'Fh"Fd&Eb$>]"CVLf"B^#:UAXEbBc"DaFXF^ EV>[Pi(Yo+CdMr&Ln#Pl'Gb'<\$?^#9Q;M=T:XBa&B\E^C^4V:_ Gi&Mj#Be!DXDYFa)8Q"D\C]$Ba Dm0Da@]Z#Bf)E`#Ca'DaI[Li#Li*Pi%Jl*Id#D_Fd>M!H_$C\!DW%S%9L=M0L)>?U$3RW!F/)9>JBJCCJC;L4I@O ;EPIAS ]Bi(Ll'Gi!A_)=YEc?c#B]Cc @X?W1@ +@'> 8R5HXp1Pi Qv0[|2\v4Vq.Ul+Tn-Wt.Ol(If%Jr0Wy0Sp.Zu,Zq.c8n7mDl9]t,Rp&Ke&Rl&Wy0`|8Yu/[{:Pu1Pu2Pm2Li+Id%G_ ?a&Im,N{4Fg'Tl*Wr0Uu/Rn7Ss/Ry0Yz7\7Y|.Z{7Wu/Sx<]{9Ty5Lo-Vr*\w8[m'Nd"Nf$Ld"Or(Wu+Rq)Om'Oq-Vw-Wl'^v*Xq*Kf&Mj)Jg'Vp(Ph$Vm#Pd Rh"^u3Gd#Pp,Ln1Qu2Uy/Xr*Po*Xu:Wp&Vu6Vw3Jd#Kk+Np5Nm%Qj&RiUq+Ee!Mg&Ic$Je,Pw*Jh!Qj'Pl/Qi.Kg'Mb+Xi,d|;Ld)Jh"]u0Zq'Kh/dy.Uo%Im1Yu1Nk#R{.GiTk#Hh)I_!Cb C] 8W?`Bd"C^Oj&IdQo"Qt'Xu/Ts'Qk Ww-_s%[r-Lh&Je!:X!B_"Pn&HcTl+Ca@XG` ?ZIa!=[NiCcBf%@b%Ij*Rr/Uj,Gc#C_5G@]>S?YMh&Xk+Pk&Ma"JbGd_{(^r*P_ Th&;K9Q4M?L:RGOBYJ]?Y A]GZScQhJc"@\"E^%BU@Y:X7PEY?_J]PhDc!>UIg(E_GdSs"Lp"Zp'ZjMfH`Ng#Rm(Jo.Uv-Ik!PlUn F]C^D^B^?VEdLn$E`HbJdRj!Nk)Ec(Vm$Ef!EbNh"E`M`=]#6U7\CjCeDdFeOr,Tm&Os4Mw;Ps*Ql*Zy1_AL`Or*Vk$Ms'Jr4Hn,Pj!Wt(Um"Pj$Pg"Sp*Eg!B`GcJbTt1Tk'UeRdOj%Pf!Pj'Hd Gf"Kk#GaId%H]L^Jd"Fd$BcJl$HbGe!Ln&Ke"Lg$@Z"?`Lj&Bb@d!:[@[Cd+Jj-Jm3Il*Ul*Mi$Lm!H\Ig"=`$Dh%Hj)Fh+Pr*JfLk+Fe.Gd#A\"Ad%9]?b"Dd!Ji(JlOo%Nf'Sg Db&<\Bf!Ki%Gn&AaGa"E]9\Ba:O<_ BcJi ?c";X=^"A\Ge Bb =c!GbF`Aa =YLf&Dh!>a=` A^^@a#6PAWG_>U@S5Y6X4L=NCa>_!:Z!9\$^=ZBWG] Ce Ie);XB^!Ee Ce#>`%BS?Y>T;R:[B_(>TLf Mf,A`*@V'Db!Fi#7`"B[=](:X!F^"Lb+Fb&Ml"Pp*ycsT*>*7<2ECS?1B@R6B,>6>AH!77FL%KCI@35(?:58B6D ?O4;:L8K@M,E8MAG?I4C2D)B#3 4J/I4N=Z*4N CP&5.I1H"30N=L4E2M *C3N2B,C3I0L!<&;*@3K7J.>:H>JFV"6K 7O3L AY";S:N+H2O:Q:T!1Q#(I0L3F3K*J/F1P+H-D1HCM1J4X8P:X@_%(M/L9T*N)A=D2D=]"7S)G8N7X1L:R!:R-N!@Z#=X#Jc&E_#@\"B]B[ LdPbKg#Nf*Ge)J`Mj+Qm)Nh&QbGbIj)Fb#Gd'Kd'Ca$Ea$Fa@V @V)Ri+Pc!Lg'Jd!Gh$Lh&Qa[n*Id%Oj*e}?Ql2[yJSuL?\EiMj$Og!Ge%G`$H_#MdMf"^m Xm(\n-Sl'\r*Sj+Xs3bu(Ws*Sk\r&OfXq)La Jk+Pl'Id KYSg Rg!Ss3Zr,Vs0]z@[n&Mi#Rj"Wh%Ue(Zi-Ne$Kb!Ug Oe%N^B\H_H_Ef&Og$]t4Qm.LbG]FZ 8MAXIXGe%G`$Rk$Ph+M^Sh%Yn'_o1No+Fe*Ie*B^$H[Qg#Nc'M^MdKa L_#K\'Nj)LaNh&A[J]Mc$Ib)D]&Je&Hg%Te Ma%Ga#G\?_"E_*7P!.HI\Cc Jd%G`!H\*?]&La*.EG_*Md$G[Pe!Pi#Kf$Ha Ic%C[";U?YKfCZV3YDa'Hi&B`!Ni(Hb'Jb+C\#C^A`%?`(>W ?XA]=]D]?_ Gh)Eb'?MJ_DWOc!Md"O_ Jf$AYFY"Hi;=R,?QAT9M=K9Q>U ,O9XAL:S=SP[I^"6V#=\!:KC\ H[>S=S>S=O1JEZ!Eb"MZ?NB]D[(7N!6V&BS%?P$/Q=R>U@a!I`#BSJa%J_)J]&?T(2HBYCY Kd(C^#=N=ON] war[:G#-=7G

,E"3MC^.GW!;O%;O,G(H!7U'G^+4L-D.I.J/M3J,E+C.I8N=K0>HS(CR5J3J?O)G*N.P5O2M!2O0J)LE&E%C&@1J1T0Q0M'F'J #?'B1K1L4M7O;]!:W/O:Y T7N-N.LCc"8T5N9P3OD]'Pg/=\#;^$@[ -O;X"Hh/@\ ?R=R;X#+M1W ;[$Vl-Wu(Nj)Qi,Kh+Ge)Ja%Pl#Gg'@a$Nw?Rq,L]$Ca!B_"A`!?YOm)[y.[x-Ie"[w5Pp,Jk'A^ Ij*Z>Dk(Kk+Jd$Mi'Kk)A`!Km'Pv2Jk$Ss,Ys(Ll-Pg(Mj*Nl-Gi$Np-Qj&IdVo+X_iEOj&Qv;Ln,Mg,Km-Vr(Ri Ia Qj%Qq(Su,Tv0^6Zy0bw(Zk$\v0St+ax-\x4_{<^s)Xt'Y{:Lh)Pm/[v3az3Zt-Vy6ay'Rr*Zs2Zw.Os.Xt/Xq/]Ab|4`{)[u-[{UE_&GYSi)Tk)]{(N\L`(^n+L]O^$Ym2Mh'Or&[r![l&e{0Xr'Tm*Ga*Oj,GVTj'Og#Rt*Ej">_A\Jf'Qm-Vo,Om%Ie)Uj(IdNdGc Mc G`%Gg(C[H\ Eb#F`#H_Oj!Fk'Md F]MgHaHeXu'Ov,Wu,Ml+\u1[t,Sr'LgShNgNj#Ie!B_Mb"Jh"L\?XGaAZ@[?^Na!Ni&EcC^Vn'Ke_r(He&Mm)CZ"F[NhQhQj!L_E[?Y@\ Ni)Gc#Kq'HgWm%Un$Xf$Vo*Sl$Xu+Sr)Qo!NdSj YhXkTi[p$Vq*_k#Ri(Sn(P`SfMhRi Ki#Gn!Qs&St%Su&Kc Je"He"Rq)Mn0Rp&Oi!Rg!OfPcLbLcFi&Gd!Sl(Xo$[v)Lh#G]Id#>_Pj&Ss%Ii$Hc#Kh'IgRp+Go+]v)f{4Hs/Wu#Vt'Mm!Xk Nl(GdRo%Lk(Vv.Ps'Rt+Tr'Vv4Sk-Md"PiQj%D[Mh"Ad$E^Gi(K_!B_D^Rj$az2Mu-Or)Wm#Tq-Ec!>WBa>`H`HdLeCWLd Hg"@['D_"Hi'?bUn'Kg(Ka$Mb"Rn(Fg'Mp-Pn(Oj%A\%Oj)Kb$Nj/Pi$Zt(Jh)F`Uv3Qk'dp.]o-Ts*On*Ll+Gd,Nj)Ru&Lm$H\I]Nj,Mj)@aFg!He!Ba>Y&Kb!Cb Hh*Zr&Le$Qm#Lm*C_"Ih$;[EaHc"Ca Fg#=a@eE`MhD_DbCa:Z?Z C^EhLi LbB]>`!Dc$>Y@_$@^%4XD\A[>`=\Ba!Po+=_#Ca"Ac Fe!H_H\#G` D^!Id&;X#DUF` 9PHXBQ9VIc(B_%=Z"Bb'd!De-xfkR9T29Q'3L&@P%7K&6K;M6G#D2H 9I(8P'1D/M"AM! 1$H!=!@.E'?+B /G2A0M)C)@7N">]$9R#8T&BV5M?KFU(@Z7M!/N 0M1K1I;Q 6L4IAT"8U)+I-B,F1GR;H8KBW!BW!?ND_"9SGZ!DX#Mc)Ib%Ne.Tn.Pi!DbSn)Bb"Ga!Db&Gd*Tn/Je1Mg*Ln#@b Hg'Ig'Ia*H]!Fa'Ke'Kq-Kh'Uk&Ng,Mj-Di/B](Kb&Og&Oi!Df#Ps-@b(Rh$_u2Jf!G`#Fd!B\>YH_C\Ga'Pj#Gf,Yc#Wv-Ss'Qj&Ob'N_%L_ Wf-`:Tw:Qs1Zq/`u._w.Lg.^p,dw1d|8^}3ev1f9h3\f&]p*Qh%Pj,Qi/G\'Ok+Yo+\u3]{4Qo4e~5Mq6Wt5d|:Xr+^u3^u1g:`x6Ps0Rt5Xo1Rl0Qk![v7Ys6Pe+Qh,Tp6Nh.Zm+Kp+Jl+@]"Mc"Ji+<\&La(Id,Oc-Um/I`"Wq-Oe'[j#Uh*Qi$Pn-Vq+Sn0H]M]IV ?RH^%Mi(>Q!D_&:X@Y Lh%H_!Of)Pe'Jf%F\!Kf(Ie#Mj&Ma%Td&Uj(Gf&Qd!Rf"D\Je!ETAJP\!AXC\'Ib'BZ#JWAW:S@ON]BX?JIU;MF\ F_BYM]$@UHOGWDZGTG^Wl(Vg)Ub#Ul2Lh.Qh&Qb"Sf$Hf&K^$Ng#_x5Pk.@YIe(H`&Ug$Me"D^!@U$I_%Nj/Tg%J^#D\ E_ G[H_ Qi%Sr/RaNe$H_!Ib J] BYOf$K[FZG_DdTi%Nh'Ur(Vr4Wp9Oq*Vd"Oj*Sl1Lk,Vm&Kj'Ng(\i$Yk)Pq+Ik'Ho/Ga*Jh+Oa"BY@YC]Nj$Ef&=UC^%B]*B\ALU4RE\G\"9W:V=WG\`*:S!CS#CX@^#Fg$MhHd"MZ H_!Hc$Hd(6Q B^@^ @\!A\"BZ@X @]EXATL`!Dc#Hf%B^I`Mf"Hl,Hd&Tu,Nu7L`Ci$F^#BZ%@]Jj1Bd-I_"Oi&Mg%F] G^ DX EZEe-Mg:Hc0GbZ$>^J_B^Hb"Fa"=Y6Y)V"5S:WC^?RCWFV)F[+1W&2P":Y 7O6R7X&HW >XCZ;T Y%9X"+N4T9Y$=R 5P5T5VFh(H^#J^!@\=O2G3>1K1NBSB[:RC^%B\J_"B[>`%7`*AXI^Jb(?]#5M?U8]$AZ?S1F>UI_3P?W=Z!@_$5Y&9\#A^ Lb"Mc"E^!Pc$H]%G_$?Z$GWLa+deKCX.:O!6I>Y%IT&0M"MM#;R&4O=L5G:XCQ1J,F.F0N6U >RW#2I=V1I/A'I-I/N;D;S1Q8Q9N/A /P-L&D&@*=,E+B%@ 3L+J"<)H:Q:R)H3L -E-G8L4P ALO` C_>UDR5J/E+C?R9O+E2J4X7T=Q6ODZ6UB[B\$Eg%9VBYCUOg#Ja#C\Od$Ji)D\Vm'Yr+Rm!Rj._r)Qj+Mn#Ie"]o^x%\m$KdLm MfOp2On3Yw2[oKiVn&Ok Tr!Om&Ih*Gf#Hg#L]J_E]B_B_Mf)Da#Mh)K`Jk,Mj'Lk(OjWs'UoSn$Jj)Zp&e|-h~*\o!Oj#Pr+CcOn-Kg#Rm$Mu"]{(Qr#^n(_s'cs#]v+_v'Zu+e|0Rf"Mm*Mc$Tl'Wv/a{+\x+a{-c~4a|0Sq+_t/m2gx,Zy2b:a.Tu$Tl Li&Ri)Yt,Pr/Yt-VlXs*Pr/Xr.f@`@\r+Xm)Xs1\s,Zv&[u-\x*Zm-I_Oj%Ss/Rt*GgJbJ]Ui$Ih%Qm1Lk/Fb(No$Mn)?[AS]l7Si.Df,Ne%\e#Po$Ff!\v)a}(Xs)_y;Zp-Wm!PfIeVv"WiPeBbB_D` Qv-BZLm.On#Xm(Oo%Qi!L_I`Qj,Rj#Fj$Qp%Wp&If!C^HaGb@[AVC^>QCSJYDVKg#CaGg'Tr+Pm EVJ]G_;XAd?` F^>XEYPd IaJfKd!Wn+Wp#Ja Me_k!Pr+TgRk"Oe Rf"Ki$Nj!^r$[q"PbVdR_Zu$\r#Yu*Od!Tg']k _o#Od%DZRj&L^I`K\Dd@aLl(Qp,E_Bg"Vj I_Wn$Rj!Sl%DY@]Id%Hk#KiPh$Gj M_IeSj#TeTq"JgKc Xm'Vj"Tj Om#I\BUFbH^JbE] A\>VDXJ]XhDcCa?XE\G\L^D\ Tm+oJB`Ie'Fb(E]!@WG\J^J_C^McLhL`@_J[KeT`M^@^G]TfPh"K_B_NhHaB_F]BU>]Ed@dCg"Vl"Qm%Hg"DdPhRj O_H\JfMfUJ_>_A`$Hc!AfG_!H`!Kd$HZFd%H`#@e#EaG`Jh Ol%HPGe?WGX@W9S@\Hk"Ig.@RKh"Aa%=W;[B]=\=YDZ1R6ZA^=[FZBZF`6V2S6OLcH_E];TBW;R3PD_#@_ ,O:MG^F\G_?Y5RX5Z6M?RB[DREUC]>Z4UB\"/N8X9[D^C\/M7S3T+L.Q3Y@X;Q5O4Q3R@X-R4M>W:OBW?XD`!Hf?]'N3M@V@Z?U,M7V?[>UC\A[@`Eb Kf?a">a @d#@\LZN\ IbEa GUF^$vaҽ\GCR->S&5P)B[)KT&3S).L#6W+=O%SN!*?:P%.E1E,O'/M"8X%5R"*H:\).K +L&E2R".J+L!D,S ,O$)L)I(D/I!@,H9T!,N#7V+K6L.M)U'+QC/K$C,N/P"8X'2O"0RAc,?V#4Y&:]!6R:X*>R"9]!)A"/%>*@6N3NE`3S 5Q*L2L0QB\!4U!;TEe%G^"Ad)Ej*Lj1Mk/Da(Vw5Un*Tn+bo*bq4Xj*dz3d?d:i4`{9]y3V~4dEWr*Z~=Wv*Vt*Ip)Tv(Po/?aUj'Oi)Ff!Oo/If)[y3Qj&Fa Sl'Jm-Jl'=^ D^$Gb'?^%WCa$Hb*Vi#Ie(Dd%Lj"Ld&Jq4D^&Tk(Wm%`t(Yp(Th&Ll"Hb C_#Ql%Pj#Hc!DVE] Kh&Jb(8Y$D^!If'Kb#Ok/Wl,Id,Qg Qg Hl/Ke,N_ Ji#De"Jk(Kj(Mm+Ki&Ce Io/Fd"BcBd%Aa&Fd%Kg%Mg"Tg#Hf+Pm-Jh%Ig%Hf$F_C[FbB\?[Op,Lc!La"JbSg%A\Gh$Jf,Gf.Re$Uk%Pd$H`H`!Fa#Eb!A_"I]Mg&Pm&He#CTE`!Uo%=`$F`&>[#H]N`SiMi#C\@\=\$G]Sm0DdI`F`Pd ?VC[=Y@XD^Po+H_!C[A_!9PDa%Tk,Lc$Rm"Nk%Fc!Hh$Nd#Eb$@XSj#Hc$>_Lg#=ZA\Ml(Yu-]z9Vp0Rl*Ns Zs(Op*JfJh$BZCa!Mn$Mj)Gj,Bb!Da!Ob!Ka JbL_Ol#Pk(C[QaXl#Oo.F_IcB["<\$Mn2AYF^ OaMi(Kg)Gc)\|AOl(Lq'Nj-Ed'Hg!QhAc!@]!C]%Lb Gj*Kn0Zm&Qr3Om)Jd$Ok/[u-Uo%Yr,Tk$Gg$]u+Rz6Dk2Di*Ea%Om'E`"Og%To/Lg*Uo.Pr(Ll+Fk+Ck%Mn&Mm*Cd Hi-Ml.Gf%Cd)Ou.Rl%Wv)Ki*Mf$Nq/Mn.Qv(Fj)Ms*If#Gd%Gg(Rw1Ac!Tr*Qp%Lo'Ik)Fj(Ww,On#Pm(Ff%DgHl%Lm'Jm-DUAXHcJk)=d(He%@_4\!/P8SCa!?\!8X BcCc.:[+?`*;SLc)@b$Lm0Hj4Ac-Hh&@]!:X;]D_ F\$=[!A^#>\">\ :[$Fc!Fa"d+5P:ZA_!:_16O=]!1[!3R=Y!5W%8O@WDe"8RA]8["@b"5N4X?b!6P7O6K-T6O?\0S ;]!6]?]Qj%?c?e%?^@a#Da$Jh"C]$BSSh'Fb+9^*Ie#@_)AY"If(Lk/sfѽ]{=9O+BX6AX+C_(CT&J]"B]*AP +L.N)@3E3H0L6N2L"9R'AN".G=M/B+H+J2M?R$A&>)L'J6T!+E&>*B,B.J/K#=0M&G#@%C9_%)<)? *G+C1G:_':I#8GAUJ^#Da=M>R5W!5R!0N%44-/$?^$Ga&FXLj!G]La#M`Qj%\y-Sm0Ne(Le&Pm"Lj!Jd!Mh#Ri)Rn0Qm'Po&]u+]y0]s)Ql([m(Xs.bz,a{7Zw.Xu*]}3^t#Zt)Sg,]s0Yr,Zr,Yw5[v-\v*Qd"Qf"Ie%Kb'Nb!Md"D]IYHcFXRi(Tk.[v7\x6Xm(^z/b|/_l*NaVv0Xh&`u5Xr'Wn.Ol%Rl(P`'Td%Ug'Je&Tt2\x7Qm)Tj$\o&`q)Le Og Rj&Lk.Ol2Qj$Ng"`u0`s)Rm%Wo-Ph#Si%Hj%Rr!PfHh%JbRk&If#Qj&Qe)Tr,Pn&G^WiSk%Qj!JeOh"RjNgEWH[Vf"Ki#E]BYE_F\E\MgE[GUF[A]C]Oa O^DUFXT_L[HW?NE_ Sj)Ll'Ki!Pm(C]'G_C[!;TE^!G_$Mh!Mf#Pe#Qb*Pf#P]Ti"_y,fv1_n+Vi'Ng&Se'G]Pg$CPGYC]E[?UALESBXSBXX Jg Uo!Pc$EXPf(\~Bgx+l}+s7_x4Xq-aw-_v4]q(ZfUl!Yi!^s+Xe#fu*Xp$[u/\p1\r*Lc$Uh#Ih$Qj$`s)Rd"Uf#^l&[s(Tq*Wi(QbXa^k#Yf&Wi"Ym!\r+[x2H[W^J_!Tm(by6]v8Yr0Uv1Yi'\l$Un'^u&ax2]z=a|8QrZy.[o!\n/NaOe+]s4Tf%Ni"br%`u.iw/Xm)]u)[u,Jd/Rl7Ok,[v-Qn*Jj#Pl,Lc#Ge Qf&Sj'Nj$Ts+Zo3Lc$J_ Tk%Pe%Mi#Pb"PfSm!Wm&Od Id,Zj"Ul'Zs(Ym,Wm"[mOi_lTl%M_&D_!Ts&Ij Kj`x)cp,Ga#Rg!D] Mk)Pq.Rm"UpVr&OeVt$Zs%Ql*Sq*Li!XlTo!Ok)LbSk!Sp+F]'B]&Eh6Ne&Ok'Ol&E`>]"Gk0K`#Hi-Lf![p2Lo=Th2Tg Jk"On$Ol1Kj*Ql,Lg)Pe!Nd!>]'Le(]q+Ke%Gd-Me'LbQj#Mh!Me#Mf$Ib$Qk)Kf&Ue Xr#Nl1Sn+G_ Nk!Ln+D`$Oe#Qg%Wp&Tg%Pi$Jf&Rm.Uo1Pi(Mg%Jj$HbKbH^!Jk#Mg$GeKj.Wp"Zm$Ok+Ok.Zk'[q4`q4Wm-Mk3Yn(Uo*Un/Mj,Rk._r0]l*Oo5wgҿguR)H`19I-H6L0D&C?#@,J#$A#B(K,N0L6M1N/E(?,P")B0M0M)64Q ,C(H#?,D(K3Y!1N0H8R(D5L#2J)F,F&C>[.H4T!4Q8K Le)9X =T5M:P4J#@=-(E$B)G?b,?[b">U!Lh!Ii(Qi'Lk)Ke$>a&Oj'Sj+Pg&Ig&[v4U` C`J`Ob$Je Jf#Lm'Xt+D`Kc(Kd'Dc!K]So)Yu3Np*Je%C_ Pn(Og"Vi$Oj"Ii'Jb(L`#Qm&Re!Ch)Pm'Xo(Ss'Mm%Zm%DX CO@]>OEaMi!Ie!F_!Oj"Me)Wf L_Hf#Up+GbC_!Jd#Jh%?WIi$HaVA\Ga DWAYG\:Z@[B\D` LXG] M^!G`#KdM[[r-Ig"To*Ye#E[@P?TGa(@\#Xg%Th$N\ N` Ud%Kf%Lc?ODZIc*OaYi$Vl)Xo-^u,Rn)_u-ct*[u(Xm%as+w9v?e:bu-ds$jv.n@v~9dx'iz+kx,l|0p-dx,ly(fv)^x/dv0[r+dl-[j%^p#Zr(bs&ex'[w&[u'\j%Rh!^n"`q!hw,jy/^s/aw+o~=cu3`u5Ne#NfZm#^p-_q&^{9^9dz/d4f|2Sr$lw*e{-`t-_u)ReF[`s*Rj"I_Rn'Hc!Wr$]r(`|2Zs1_}8`Cl|0f|0k6Yx1Yt/by*Zq-[w7Sn(Pj*Z{-Kh&St+Vt&_v*_p+Xs-d{0ey5Xm*Rm0\z3Wv1Xy;Rs5[s)Zh"Mh+Sp'Om!Ke#Pf%If#Xl&dx%Sg"Rf"Nj G^Ni#Hc"Mq+Ld$Nk*Rl"Si&Jl+Mc"Gf$Oo0Sj!To,Zt-]p&Vt(Xo&K\TgTn"Qq$]v&cw)\q'Sl,Ml/J`"_x.St-lu&b~9Yo,Sb&Sj(Qk'Vu)Uu,_v,e{6i~5bx:bu-Vo/Qp)Tk+Wo(Ml.[o*Um)bm(go+dr(Tp,fw*_4[s*^x+^p&Yq/aw4_t.]v-a}>Uq*c~,[p+Tl'Wd"hu/hy3Y}7\r0ev.n?Zz[.9Y&5Y+NY-NX#*P%@V'6O!1S++M(+L#-L3S!/E&B#9%L,L,E'B*9*E%E)G%A#5=:4"C$6(J ?$?.J>Z-:M+G*B&H'A3Q(?Z!+BA\)Hi9Ro-Kb!La%Pk.Mk2Gg*Qh+Ga%Je,Yr.Jc$D]Oo*Gc'Ph'Hg&Gh.Cb*Ih$Cc$K^'Lf&Lj.Om2Rn/Lj/Rn)Hh$G["H`&Pl0Qi+D\ Ki/Nr9Os0Id Si(Mh)Ts1Lj0Oo+Sq.Mo-[p,Vr0Xo+]z8\w6Z}\!Hg#Hc"Rm(Oo*Jh)Vr8^x3Mj)Rn.Qq0E`"Po3XxX DVC]!FZ!WD_&N]CZQdLg#E_Lg$Gf&Id$@_Kg%Ic$@`(@]#Nk)He'B]#Pg)Hd%CYCe Hn'Gh(Sp4]z5Vs6Md BdVj!Rl&Lg$Ef'C`#E_!Ki'Pm#Xr*O^!Vm$Um$Rh!Pe(FV Pm"Hh"Qj%Vs&Ph(Lc&>PUh)Bc.Oi)F]Oe&Nb La$Ka+H`'Mb![g)Rg#[e!L_&Lb!?ZMj(Wp$\k&F]TeT`"Pb If*Lc(^l*Ri$Ss+^r%dv)^s-Ok)Zj"Ph#[t/]t/d{1^x/e:n}2`~3i?fz1Xo'Qm!Wm(d|5az9ew(i{+m9lCZu,`z+[v.b{;]q0l}-]p'Wh)e}/`w)Zu-`x3\{1_v*Qn(Xu-Sm)Ri"]s(]x*[s*Ti'^p)j~7q|7bm+^r,bt1[s1^t.c}3^x\?\o0iz1Sl.^{.Tv7gy/`w4pFb?e6Po/a|?]1Zz0i;jB\6Pq(bv2Rh*Pe"]m-_z=]z7h~6fz_s3j>l@l9u5q=f?rc@]v-Zs'ay-Wt/Us&Pm)Vs(Su2Wn0Pg)Ql&Xu*Mi'Hk)G_ Nn6@e(?^"GaAXQl+E_LdWp$Ws-^x8Hi+Db"B[GaC_DdJa3OIb A[Kc Id$P`J]Dd@]"Hl/Cd"Ed'Wj"Pe!K`%JeXg#C`"A_!EZ#ESL[F^AVJg"Mh&Gd"Uq.?]#Ac"G`LZB^@SSGe%Uk+]s3[r.`w(UkYk%H]Pl'Hi(J^Og&Rl%dv"X{2Nm$QeSk$\u+^y3\o)Rl%Wn"VbUe%[r&La!G]Le#^q,UaIZJ_I^ KcOe!FbNf!A]=VL^LbG^KcNe"Ib Ok McVh,fz?UbKf"H\HbMj%Pd"Og&Tf"Xi%J] Pd"CU>X$>WAXC^F_=T?NBZCWFZDd#@]"C\Th IaNd"N`?Y9OB^!Oj(Mo*B_Nf"Rl-Gg'A[IcF\O_N_Vi UfPi"Ef$Nd(hy;Sp/Mm*Lc!Mf#Wg$E] Kd#GdD]LcUfOe K_Qe Jf%H]NZN`$N_WeZn"WfYbYgLd[b"bh$_p)YjXfYgcu$agVf&Qf OkHh!Ff!Td\dE\Ig H_NdM]Va^p*do,Xggv.Wp-Si*P`#Wf$GcKYQWXl)W`Kd'GI[o*^u.Xs+^s,ds&[r'Nf'[o(Zp#\q']|1_{,`{5c{:^n(i|/cu'\w0ax,dz/p;bx/a}:]v*_w,_y.d~4bn$^u3_jev)fz+dv,k@dn)e{$^v1]w)`r&dv1Zq#_x%g8_z0Wi"`w0MhPi'Xw4gv*dx1fy4Xi#[p$Wq&Ym$dv1_r$dz(g/Xw6a|3f;`}IWv*[v&Rr.`p(Ws+F_Om$I_M]$Le#D[VeRr+Wu?Zl$_Djy3m=g2_|9Wz;Px:]@Ux4Ss0Ww+_z.Xv-Tw)Qm*Om)Ml OdPl&Qk'Ol)]s/aw&_q-Vm*aw&d9a}7cv6]@^v,`v&Yn.eu*`v/\w.h}4Rx1Mn0Lh LbHePg$Kf"\u6Mk+Pm,Le%Nn"Xl%Ws0Og/Zv+Tz/Wu5Jn1Ri#Ym*au*Vp'_v,\w@]}?d|ex4g}9h|5gBf~Bb?c~7_};h}6o}-o{J7L!A.J:S#%F+H(H)A*B/P"DX#/M4W)4S-L .I.O8Q%@Z![?`Cb"?RE[EY=[BZLg&Pj!KcLeQi#Ic!Pf%Rf%Vo,Nr+G`Nm%Wt5Ys(\t%Ne*Wj%CZOi'Nf!To&Ol#L\L_;XKcKi*Hf%CbL` Ol,Up(TiMf!Oc#`r*]p+Wr%e{.ar)dt)^l Tk!Zn!]v(Tr(gy*p?`v+\t(_s+Xh [k[n*Uf&NjPbF[B]]l$Ys3d~4Wr-Xr)Wg$Se%Vc&[j.]v.Qj#Lh*G_R_!Ve"Zm&Xj+Wn$Us)eA[t)Tq*dv,Hi&]w+]o#Mi(Xu,Wk'_u*[x7Vm+Zj"Wq*f~2e1[s(^y1e{+bw)[}7d{1a}.by1k:Zx+[s#s.w4pEg|0;l@h}3_9`s.Sq*^8d{3\u!Wr(^{(`t'Xq-Rk)Wt)Zx(dw*cu+bn'Tu+^y2_u-a|=[p3Zo1\r-a|/Ww0Yv+Xv-Zy+Vs'Xt(Pv&Pr$Vm)[nMt2]s-Wr,Km1Js(Or-Wz.]u/Wl \z+a{:az9bD[l'Y|0Kj(Uo)\v,Ts*Tv6Yw.`t2[y7Tp-Sn&Xs-\y3Nt0Y=Nl,Yn(Yq&Xw+b~;\{;`~;Wu3^A^u6Mj%b0Ql#[l&Xp+Pj"Pd'Ge$Jh!Ai(EaGf&Mh*Wl&Qj,K`&Tn7Ok+Zv'b~9Tl*RfKg$Uu6Ij3Pm1Ki$Ji!Jn)Ws2Vs1`v+[r+d{.`J]|/hz/i<_~>`y.F-L"1K0M"DW&AX$.G5P#-H&D!D>*I1L*E2T%5V%Gd.[n;Qj5Y}@Us;G` Fo*C["@XH`!Hc!Ed*Id)Lf4Lf.Ou6Zo-\y8C]'So0Gd(^x;Om8^p0[o/Qj*Jh%Ml,Nm1Ph)D^(Gb"6T;NCW ;NDW#EV Ab,@W#Ca,Kh%Og%OdGe.He3Lb(Gc$@^*Li%9[%Bj+Mg$Kd(Ni'Bc+Lf/NX!Gb.Qn0Rk+@_(Db,Cb.Na'[t1Ml+[x1Rr,Mn3[r6Oi-\s.Pj0Qm6Xw5]{:[|4Su1[o3Vn4Wh1Xw8Or0Nq,Nh-Bh)Sf.Ro,Rh)Ts(Sk(Si [z.aw1Qr.Og$]u*]z7Sm+Wp+Qn3Rk2]x6]t5Mc$G\ Ma&Rf%Nj/Fg'Mg$Sg Pp,Mh&Lj)\r3Mi+;`!Ig$Il.Rn-Zw.Ke'Pf*H^"Mi&?ZB]Jd%Wj(Xm"Xb"G^Nk2Vv6Hd%G_ Nh#No(Kd%Kd%Tl.Rh$Mo*Wo/a{3Nu*Pl+Jk)Xl+Ye(Uk(Zl)Sr1Jn/Yr&Zq*Ri-So6Qg%Mg'De&Lj*Uo'[p'Qi$[k$cu+Zo#Pj"Wt-Ss/Xt*Qf!Qe!Og"PdQjQp-Ws,_AKm,Um"^h!Zt'J`$@[ L`'Uj(He)KeK] Id!Zo)Sq&QfRf$Xp1Yl*Sm*Ji#K_DWn:ir3m}.f|9gJYEYr=l=qFk8gHl:i~@fw6j?e>h8cAl}q̻Mg1A\(:V"1@5Q,1L &D"B$?0G.G0E5K&8'I!?,@5 "6 'C#- & ") *F4PBb$4P/K=V9Z$5S=X:P$E^!3M;U=`'Gb'Gb%Sm$He";YCi!Fc'Nb">_$C["Hc'E_ IeEb#Le#>ZRn6Ph,Rn*Ig"Le%I]CSUn/Kl&Sp)Vl)as,Zl&Tf#Ld$Xm+Xl*Vn-G^!Nr.IcF`Ng$Sn/[p)PfPi!I`%Eh-Mo.Pr2Ge!Kk#Pi)Pi%Nl#Pq'F`Mj"Lm-Mm+Pe%Or/Jd!KeTk2]x/Wv?Ru/Zs7d|7Lo$\v(Tn!^q+Mk,Si+Tt4Tl-Qr-Oq.]{3[q3^z5Tx5Jn.Nm*Lk,Vv1Ki*Fc"GcHh!Pp5Qs+Tm(Jc!Gg"Ok!Wv-Ue!Vs-Rp-Pl)Hl-d{'Rm&Xj!RiRh#Xl&]s-Mm/Ym)Mh [o%Pl$Om.Vu3Jh&Ul$Ql+Pg"NjKi"XfRcTf"Oc"Ld$Si%Vp*Tx-Od^k#[j[u+Mi!Og%Mj)\o+\l#_v!Rk(RcMjWr9f?Te#HcGaC_FbMn-\s&Ur,Zt.Zl%]}1YsZr ^t'\g[u(]z2Tr&Od%LfSoPm'Tl(Yr)[l!Yl To'_z(]|'^v`y!i-Xu-Mq#Lm"Wv1Sh[r ZoRm"Xs&I`Pg Uo&]y/Mj"G[=UG[UiHbIiCf!Mg!MdRo"\{0PiGbMhGa"K`JfKePu+Cb#F^IdG`K\Le#Me%F\EdGaJYPh&@W;WA\G^Li#Rj Pd"Kf!MdHaHcGXUeObK`Hc#Oj'Pi"JcSm'C_$Gd"GaTj QbI^NbD]MbBYTi%YiPg#Pe![iYq Qj!Pl&Og%^r&c~,Xj Yk Y{2Wj#Mh(Pj)Oe!Sl&HdRl%LbVj#\p,`COj ]v2Ti#PcPeHg"Qq'Vx5PiLgNj%Uw5aZz,h9h.m.j=e1l-m4f|.h~*i)^y)]t*Vu.Vs+f~6i{5g;\z5i2k8m?h8j4dAu@nBtBr?b8Nv0f:`s8k8\y3`y2Qs+Xq'Xu+ex0h2j6^q2l~4e|2c4\{8Nq6Pi)Rm-Vo.Xl0Yr3Vp+j;g}7gAd;h}1m̹=V3=_+3O(+G0I%:!>9$B,H+B"/C3K/; &8,D'D:&B&>#A%>#;5 &;+L+F'E'B*E*B6N,C@Z#Ia(?^'C_*Wl/Id!Hc!Me%Jj%2V"3O:T ?U&5TI\G] Qi)Lh&Pp-Pp+Rn2ap3Sj&Lj'J`H^"Kd,K[Nf(BT!E]H_"DMFSPe"We$Yo/]l0Og(Kd$Qc!Ma"D]&F_%Md'Pf,Wp+Ut9Hn/Pj$Ml+Sp(Sr0Kh$Mg*Mf*Oi,Vp2Jh*Vr/Nn+Ol+Ec'Pn1Qo/Mi*No/`}7Ql+To.On)H\&Ol4^k3Wt1Wn#Nq*P` If(Ri$Sl'In2Rl%Ij,B` Lj&C\?[7S:ZQd"Ol(Jj!Fm'No-\l(Sh"Hc$Ol'Hh$Xn#B\!Oi#Pn-Ia!Vh#\n&Kb!Nd%Os*Qr(Vs(Ph+Li.Le$Kg#Bc%;_'Hh-Zj,PjRf"K`I]Ha!G_Se#Pk&On*Tj*Sc#Xn!^n-Xl)Rn.Sk+\s*g4Xu.Oo.Vj&Sj"_v.Ro(So%Qr#g|-]y+_y.c|6Pj!Vp-Oi He Hg LjJf!Oe&Qq%Ge$Lg"Uk`;Bc#Oo&MeM^To(H_"Ec(Me$Dd$IbMj [u'ao*]w0Mg#H`>_Rm)Jo"Rq"Qj'HcZz+HcOm'Lm)Ok%Rn'Pe!EdH^MdFa?\#@[A_K^F_'Nb%Oe)M`$Qe&Lf%H^Ni$]p)Wh#Mb Ji%Sl$Hc'Ui$Ro"\w&Ws#UgJd#To+Ie#Jg)]q/Uo)I^C\O^ C]!Uk(Zn0Te"Wg$Of%Sl,_n,Yn%]p+Ur._u)Um'Vm(Yu1Zl]r(Yu#[q.Yr-Of,Uj-Vr/aw1Wp%Xl'Uj'Ok(Mm+Zs,Nf*Ja)Xl-Zr)Yo1Zu/\w.Tp%Zm#^v,]x,Ur+at*^s*Up%Ge(Um"Jq/Ts.Zp/Su+_x5]r%Ug$Kk'_y:Nr&Pn*Wt3Tl1Ji$[m Nj(Uf!Zp'Vm'[s3Yj(Wo!]t']w,dq(Xy0Us/Ol)Ud(Tr0Yx(Ws(`>^z0Yv0Ul'\l*dz/]x)Wq'du-X~:Vj$e~3_u3f@lAe{3_y-Xt-\w.k4j}2Yt*e~.dy,e}-ey2Ys*_w-dz(Zw3]q*[l'as,`v'az+]~5^u+Yv*]s#Uk$]y1Yu+f|.`z)X{,Yt&\k"ex,izV#E^!C_(Qh%LcR_@d#Ia&Rm.[r3Kj2Ha$Ml$AS?O/H1LBREV$@U(Mi%>VKb'Lb&D\!>S"Uk5Oj)F]$Dh.I_"Tj.Lj.Tk+F`Ia!Ie(Ge"Cg&Pl.Vp*I\(Ml4Km1Fg1Gl.Rj0Jg)Li,Mj/Zy=SlVv-]v2Pm,]u*Ni%Li'Mc,Jc!Rf)Rm3So(Pi%Ni$=\%Fc+J`Jf"Ga%I](Je%Eh&Lm'A\!FbNl*Lm-Nm,@c!C^FdBb!B`!Ii)Me!Wl'LfLa#CaKg!Ng+Ml,Zj'Mi(Ml*Nj'RbLd&Mk&FaQm(Oi!Vv1Mj$Yo+Wq'Oo%LfMj%Ko/Na I^!Og[v*^z/Rn&^u-Wn$Qi*Og%Ug Yi&Ri%Ki'\p'Lh$Ll"Xu3c-`{'[w*Zw,Yv,Rh'Ms+Sm#Mh)Vh%Sp3]o&D_Ho,Ke%Ce#=V:KE^Eb @]Gb%F^JaZw1]s0Wr&Ic"Gc!Ff!=` Jh"Kf$Sj#Dc KeF\B_FZLi(Kf(Jh!Mn$ReNe Xs'JhQgIm%Lp)`s3^t,^t+Rl'Wn*Rl#Rf"H`P`!`j&_n(ez1Ym'`y,\f Uh'Ql+Rr/Nh$To#^u'av)bu%Lj"Us(Yw/Wn2Ne'Lf&cr'\s1\n/Rq*Vo(Sk,[o2[t3Wy-Uo+Wq,Uv3`A[{<^{9i~:f}?Yl/_u.`x5`y8Ws'\r'Rs/Zp&_x,[w0Zu._w*`4d|4d~6Sn-Zx1_r$bu'Yt,Ro-Sq(Ti.Qq-Qm'[z5ew/cv.gy'Pm Sl%Zq'Xr0\y5_u+Wi"Vp2\r0Xp,Ok$Ws'[s/i3`u'\w.NcJ`El'Wy5Pi*\t2fw2dt+Ui$Zr'`u+bz1[y0f~7b|9d|7Yq'Wl'Rj"^t0]r+c}3h}>k@n9j-u4Vk'Xu)cy.Me#Mk0Kh.Qj'Zp#cr-Xp+Ws2Rq.`y2Z{:]w*\w+`y*cv)Vw0Xx3dy:t:d{7d|:c~3e~._w1\t-_y2^v*b}0\{+Rv+^z.g~;e>`x9by0Ur-f>b@`2]r&\l(bt/bw*cv,Zv/Zo _}*i\G`"Gg#GeKl.Om'Vl$Oc!L_Lm#=_ CZGi#Fk(CaXo#Rj'Tm DfMj)Cg#Pj)Tv(Op$_f[u)bw([y,Zw*Ur6a}:]0Mm+[w,Xt/Sv1Wn)Ks.En-Hh)Qn%_u'Th&Wl$Wp,Wp)Rr+Pj,On5Ci*Sf%Wj(Mm5Ji%Pn1Jf3Om5G_%Rn*]s2Vt.Of0Hc%@[#Jf(Mi.Pd"Wm$G]$E]Cg*Kl)Qj(Sc-Ka&K]$Ri!ar-Mf,Ro/Sp4Pq3}g̺5P#%H!#A'B.J'>%@#?#>%>+H#.G-M&D"?,D*D-L#;W7M!5N1E1I6Q;_"7N6QMk0Mk/Nl8Rn-G]"Ie.[l)Tq,Ee'Mk,E_&Mk)Oc E`;^XG[ 6SE`#Ol2CZ Qj#H^!Ke(Jl/Zm/Pi%Mb(G^-@_)Hd(Lf'Ke$B_"Jh&A_ B[%Gi1>X"E\"@[>]%Ec$E`%Mf+K^'Oi1Fe0Ij4Nl'Oi(Qm)Hd#Hf(Hb&Ri&Tn-Jh&Tu2Pk.Xp.`z4Wv5Ur.Kf%Hk.Lj$Vl Cl5Ri.Rp3Mb"Oj+Ln0Dg-Zu-Ru-Wr,Sl'Pg"Ws+Tq*Ni*Eb-Nn'Sn$Qm&To'Yq*Qm)Oh%Pi(Pk)Ji"Nq1Vw*BbJeJ]"?^ Gb"De"Ip-Fd%H_!Ld"Ol(=_<\Fe$LbMs3Lf#>\Ha&Of&Sl0Ws*Qk OrIf"Ee%Tn$Rt'Rt/Rs,Mm&^~2^{*Op*Pj'Qi&_z5Xw3[/aD[~5\w.\u#`~3Xq']l$Sh%ds+Rn(Lq&Ru%N_$Rl&Wm&Qn+Jj!Gn#Li&Sp'L`Jd&Pj$[i,LcEc#C^ IeOo&N` Li2Mk&d}1Sn.Ux.Kk.Nt/Wy2Hc Il*Nf!Qk+Uq2Zv.Os,Nu)KePf#Ml'Xs/_{0[~2c?oBc.g2\v,Zm%If Oe dy2a6g~3_0`>^?d8e~0ay*^v&j>qAh1Zx+\y*Qn/Yk'ez/]u.Xw-Sp)Xx1Yv2Ol,Ts,Qp+Ic!<]%C`,Pt/Ll*Wi*[s-[v'Ni-fC]}6Pr*Pp(Sy5Us,Yy+[x-d=Pi'Xy>Xs.Wx1cu(ay,\l%Ug#\j#e>Vr&Rp'^w([n&Um+Mj%Jg#L^H`#Kh"Su5Qq*Wr,Ys.]s.\x.f{0[|-b5d{.n.e;dy/Yr,^y,ax.Xx,Wv(Xv,\t'Wr+Xu.[p'i4]{'bt'\w,[u*PiZu*Xu0ev.i|1q.]w*j7n{4g|5\w+Wu4]v+Zu0bu'c;]x)[v$ju-Yl(eu.i{0mAf@n4qP$Uf&Qn&Oh(Mf+Me(Lc%I`(EWD_D]!IYNg&Wr-Io.Og#C["Ld%Se$D^I`%?N Ba*Ga+CTOg'Pe G_!:M*Og2?^)C]'CT\$>_=X=WA[$Uj!Uj)Ol%Kl/Qp-G`$Og+Sl0Tm0Pr2Jb*Gl5Sr,\x5Pn(La(Yl/M`#Nj'Kh(Hd Bb)?S"D_%G`'K_&Lg$Jk-Lj#Hf'Ou7Fj3Nm1Zt5\p4Vw7\@`}-a}2Zt.Yk%Xs2Yr0]z9\z0Yu/_s(Un$Rf Pd"Rl'Pi*[l'az/bz0\{1Uk'b{,`z3h{0Z~;_n4Pr(Qo!Oi?\H_Wm"Qe$\o.Wt6Lq(Zl&Sl Md"Rj!DcM_"Tl&Ke'Xq'Fj(Ef!E]Hb#Pe&bu)Rm(Rc Vv.[p)Wo$Ul)Sn)`y/Vo&Nr-Mp%Kl!Pg Ol$[o+Zn.Rh#Sj&Rq+Kl&Wk%Pr'H`%Rh.Sm*Wj+gy-^}8g9Mv0Qn+g>Xu(LcKh Sq$Ni&Nh"Qp(Ul+Me#Ih'Um*Nh+C^!Qj$No'Y|<_y1dw'\v+]s'^w7Xw1Pu1[s(Ov+[x4Xs*i5Qs-^w&f~,Vq'Rr3\s&Pl)Ys.Ws0\m%]k'Vw1Pr.Ol!d1j.Zw%_m%b|2^~6_5_~6_w)a}.Vo)Nd$Zo.Fb'E]"F`&Lk'Je Lj+Wk/Vh4Mi2C_&De(Oj,Ql'Si%]u0Wk*d;gz3Zx1Xs2Qp0Tu!Zy4Qp*Yq)[m%]|0[x0_r7v@g>Yx%^y2Xr-`x0]{3V~5Zz3Ro'To(Vp,Uu)^y2Vw-Ro-Ki*Wo-\u*f|6h|0g~/l5a|1b~5c~8T{BY|:c{1_{-Rr*[w+dx2Wu6Ww2`w*]{4Xs"Mp&WfY_ev'Z|3i|2i},s-b|)s;f~6ez;^|;k8_v*ay)e|/_z/\y,nu'g|2k4du(Zw=s9i;zLk,Rp(Ql"Pi%Zp&a}.Tn&Mu'HiMiLm+Qr*dt'^v,Qo+Sv-Vo(Lj(Eh)Fe%Gf(Me,Eb"Ia"Mk$Lk*Jp)^}-Yo+az7`x2hx4[@\|6\{-Xx0j7h~_&SiRj'Og&F\#G[:RHd$Ia#AV7OI_+Lh'Pk*BYI_"He/Cg/=b'CXAc%<\"Ji-Rn8Kf*Hi1Hk0Eb%Hd&C\!If-Jg&Wp7Ur6Sm.Fl3G_#Rj-Mk*Sr/Ux@Vn*Yw8Kf&Ba&C`#Ni(Oo2Om&Pm+Ig/Ol-C`$Wm)Gm)Sp,Ot3_x2f|4[u+Wv4]}?[v*Xz0X{0Rl'Pr)dz2Zv5Uq2Sk+J`Gg"La!Qh Si#Wn!Li!cw)_}3Tr(dx)]w0fy/h1Xv5`8_2Rx;\|6Yu+Sp&Ko,PhBbPo.Pu(Mm'Zu0`v*PhVr%Nl'Tr$RiPh$To.Wh$Qr0Vu-^z*Rl$KbUq+Ia Mf Ih#Lj%Sv-Qk%Ol'Hf,Qv*^x4ay1da-\{5d7Xo'Xr'Wj']v,_}@Yy-[o$dy,h~;^u/Wq1Zt)Xv3Rl'Tr'[u'Zr ]l%Xu.Fa&Wu3[y5\u4b{0f|4j.e{/Vo%To)[n(Qn6X{>Yt.^t*bw,Sl*Rl(Sg$Ql.Mj.P`&]pLu-[x9Ts+Z{2Ys-^m&Yu']y,Xz4Vs*Us(Rl#Ss-by-^{+Yy(Vt/\v(fj=q=g.o:k?g9\~1Yt-Yv7b8Tu/^w.^s(Up0Yt*Qq)Tn&Wt2Qu+ex*c5\w4Wq.Np+X{2a}6_i)c4Zu2\4Qp'_y3Sr1Wm%[x2Nk*Hb"Jl,Xo&au*`v0Ml'Nj'b}:j}.]4`4b1by3Pl*Fh)Pn*Yp,Pq0Kk(Dh"Id#Kk#Vr.Mg!Wj f|6Zv-c{1cy-`{0`w+`{0h1h8g<`~.fy+e~4m7r-hAo?jC_~9g@d;f4h.k1a2hu'ey8m?gCl?p;n>f}>h|;WsX(@W%@SOc%H`$Mm.J_*Rg)Lf#\m0]h.Pc$Qe*Hd&Ql'Xq8Vm,Pi,Td)Pb%`r/Vk+Da&McC` CZ!?`$Lm1C`!>R9J?["9[@]&A^&BT Kh5Ie,Lh%E_'Jd%Uf!Jj0Km+Nl'Kd3Ni(Kl-Ge!Ce(Kh+Ii/Di3Gn1;Z ;WHV;U@`&El/Us0Uq1Xt3Mc,Om,Mg$Gj#Fc'Os;Pk)Hh.Ln7Gb"Xx@Ge'Kc.C_(3H@\+Bd*Vo5\p/Nl(A]@VMj%Ji"@SHd Li,@^"Lf$@\Fd(Dh'Mk,`AV{/Qo&MkI`Nh$Zj"Ro,No)Nj(Ie&Km$Mi Po#No&Mk(_z,]x.Wu)b3_}0Uo&MfYr$Mi"\o$`:Ot1Yx6Yy0Xw.Xs*Qu-Y{0Tu,Sz1Dg)Nx1Y~/Xn"Ls(e~3\w&Mo*Qp.[{4Uw7Pl#Sp%Op"U{0QlOh&Ru)]q*[q&Si"Pn0HbWv3Vx8Xu3e8_~3Xu)Wy3Y{+`6`v/\;b}.f@_0f:Zz*e~5XFl?e;cx,l:]y3`9`y0d~1Vj%Su2[w.i6^v1a~2^x'`}>_>cx:ay)]z/X{:Wt3Xx,Sv'ay5_s+`y5c6^v(Ru)Z8^z.Tk&Wu;Xw4Rj$Pn"\u)\u3Xz0Ux0Zz/c_r(Sw)Xv/Us,\{3[{7Th#Pj%@`G]Vj#Uh!KdM_Sf!Of)^t0Yh!Zs/Ys&f}/c}_}-cy-_|.i7c~9_{*b}2Rx7Zy-e/\w4dw*c{,Zz,Wv6`}1c}0`5b4p8m3c~9e=d;az2j@d6i9n5\z(Sv)\{/Oo"[y3bw,KsSx,b9j/Xxat3e2}rɷ»Tp1;O7R9IBY!NW$Vn=B^$F`&9L;NBMA[#;W$B`"GZ Mf+Pe%N[CY%Ie'To3Jd'BTAZIh!B`J_"Zk(^n+Zk%_s6Zt)Uh$Nd!AZA]#D[Hb&HZ#A\"Lh*Ml$OdGd"L]"@PBS"CWFZBREb#ObN`&K\ Ja%L\Gb$AUG\Je"Od'Wd Pb FbIg%i1qSt-j=^~@ax/h1l{0u5i@g|4g},_v.l?^@fo(S}Ag}2n7fz,^q1Zq*aw3_w/Uk'Zu%\|6i{2\};Np,^w5b|=[t.Sm"a}/^u,i{,_|,ex/dr4l9f~)d|2[p$`p%Wp*[p%^r*bw)\m0[q&Un*en!]y*Yj)Kj*Ni'Ha"Md(DPSi%_l*bq)\q-\w0\p2Xj+]n&]t-\s'g~0h8Xo2cr5gɶNb3AW'Wf-Ol-Pg2O`'Yd.Rm=Me0K`&On5So9F^!C]*ETIX@Z-L^,AUBc#Ra)DSI^/Og+Ea+Ea%Jh%C_#La"BRIYOg*Sm$Qj#C^'F[&Lg+Lf!Oc)Rf(Oi+Md1Mg%K`%Nd+E^+E`'F_!H_3G\!Gb$Ob+Pe*Ul-Qj.Qf&E]'Ji2Lc.Md.Ka%Cd+Rb+Ie2Jj3Jb$Md)J_(Oe(Ib Fc)Fk'Nf%Oi-Tp3Mj)Pi*]k-Tp2Ni*G`,Le&@Y;NCS#Oe(K`#D]'G^"Bb)Jj/Ic&Vn(Pl)Ph)Gh,Ke*Ki4Od*\p-Uo)Te(O[G[!Ge%Gj0Vj(\p9Sh.Wm3Xp0`z@nEUt=Qe(Un0Vm Tn+Y{0Z{3Xl.Lm+Hh0Tm-_:Vt0d4a7`w)^};hu1Pp-\k#Lh(Pe#Xr-Id&Pk$Tu)Os'Ol(Pn3Le"Dd%Rl&Xn&Ii&Sx2]y:Yr)En+Ig&Xt(\~;_z0[t+MhSp+Xw.]w-^y0gz.b<[r+Un%Qj$Ul)Qo,`y:Yl(_l)ix+l5f~2g~4l1j~6m{1k-m,kBgD^}>b\w3Yq2Ol+Rt)Wv(V{0Y{6Nn/Og&Hg)Je'Nr'Ws%]t0Oh-Yj&Xs-Yr2[m+Lr=On+Um(Up6Jk(Od Lg%Ni+Lm2Y}6Rq&Ri&C_DPFaLc%Pi"_t1Wd&[h'cp(bv2`t+Yo.Sr1[u<]j'To*_x*cx/Tl*Rg!f}5Ty1Vt*Nc Vf#Wh Pe.Ld#Mg(Wr3_u*]q'Gg)Xk)Tl%Wh \s,Uq+Qd%Vl#^s'Tm Vp(Lg!Qm%Ok+[t,_u,Oj'Sj&Wn IeMl'`z5Mj(Ge(Ge$Vr)Gh'G^Hj!Lg Lk$Wu&JgJXKWSq*Tm(Wi#au.Xn"B_Li'Id$\u&[p!Tr'Om$Qk*\s#]|1Ql&Ef!]t(Yy.Uv,Wv0Qj%Xq'bv._u)Qs.Xn%Yq'Zv%[q)`t*Sq&]t%fz.Zv3_{.Zu-^t(Zm(\m.lx4\r0aq.fy0av+_~;_w'Zv.]s0[o)_t*cy;`w/e{.Wm(NUSi!Tp%]r%Ro%On%Nn(bz1\{,]p#_x0^y5Zy3Zu/g9]u'[r([v-Vn'_w,h~7`:iy$e9n.o1l~.j9g~9n8l|/f}d}=`}9h=e;e:jBjq<`~/d~/Xx2g7oAi|4pBvInGqi>mDl?rj.y?k.i=p>j?mBiDg=cu4jz0^t0Zk'Yr2Sr1On.Xo4Yn/gt*cs)`n%^~9Yx/Uo/Zo'g{0v}7Yr0Xn3h{2g|3d~7b{5gu2cw8dx6Z|4^v.hy,_|=br1e}2f~7bVk*Hb'Ff'Tm1Vp4Rw6Yu.DcJh#E_&F],Ge-Ok/No1_u.]s(a|7fv6Lj6Op.Li.bu/Lf)Sm+Qp.OgIf(A^Ol7`}@Nn-^AJk)Jm0Oq+Qj#>`%Ca"Fg'Mn(Pp)[z5Ut3Xu3Kj2]m&Rv;Pk)Su,Rj0\o.Tr'Bm!Jn'Lh,Gn6Kf)Wj%Ux*Vs.[t.Sx0[{)Wu2Op+Ko&Sp/Tt0Yv!Nt+Qu-Sp/Ur3^q(at+Uq$Po+^;]v-[y4\vR{VJU?UJ_:_@d%D`#Gi(Cj!Je$4U%B^(Ce&BU>ZNd"Gh#Vl!Sk$Wx4Tk%MaD\Lm$G[@KI]Tc!Xn+ao-Vk!Su.Yx=Ss(]s,eo*bu-Vj&Pc%Jh$Ld_r)Xm'Uh"\u-`y>]s,\z2Sn'UkQl+^w-Uu(Hm&]s/_u3`z.Us+[w1`{5b}/So&Ti$Ro#Qp'Mm,Eb!Li(Jf(iANl%Uq#]w)]v1Vq1Ri&\y,by3]~1Vz-Po$\z3X{2Uv0St/^y/`v+_v%`|)\~2Tu1a},ay)Tv-Yx*Or)_x)]u,Uq%Om&Zz.[|.Ru.Vp,Rr(^{*f|']t$Vs*Yu*Rr*\2c8e{0dz*cw)ex&Zx+b{-[r/Yr*Sj*Rj"Xl!Wi$LSfr&ax*^x:p@eA_p*Qq+Vr%`{4Yy,`|2\{/Yr+Xq+`z4`{1`z7Vw+X{5Qr+Uo(\u/Zs#]m$`y*_r'Ww0az,`}8Yy0f:f2j/j4i{/u;myIjCm>t@Ca}A_y9b6c:gFe=nEl}1h|2y@q>pKmEnEp;i3l0k>aC^}6]}6a6^}0gD`~:_x2Z}.Pr&Sq,^z<_z&]5c~*l;]:h=p]CUBX!BV=PGW Cc#G`Jh+Hh&Tv8Jh%?a&Da#Lj-Wu2Jj0Po4Sp+Si+M]%Gf1Pk*Ge)Ml1]o4b{4Wv7Ql+Sm)Xr0Vi'^r/Qn/Qn,Qn%Id'Ml4Me"F`(Ph+Md*So:Tp5_v2X~6Zs(Ym+Nj2Xl.Ol.Rd"Sk&NdFdE]EVOd!E_Vn6Sj.Xr(]v-]z6Sl1Ri&L`#CZT`Xr0Pj*Ij&Tl$Je.Wu7On*Lk/Nh+Nh*Vx,Sn+`z7c~;Zt(Y{2LeEf!Fh'>ZLj#He#D^B`$?`#Bc"Gk(Fl-Lm%IcRo(Ih%Af+T|4\|3Qu3Ij&Rm"Wo*Ph'H_D`#Rt-Zw.Gr4Lo,Po&\o,Og#Qf"\n#Vo,Xd$Yv,a,jBWp(Sn*`{7`w/V{8[|;Z;b~.by*_r&c~1Px/[y8\u-bw0f}3f,n5g~4Y{*g}2a|X ;ZKh%Of#Vl&C_Li"Vw-Lk'Lg+Hh#Kh#Fg&Kg(Mf%Sm)Uj*Ko)Wm+Sk4_t0Uk%Pi#Zt*Nl2Ne'Ga$?]E\Sp)Yu.Xl&`w/b}5b>\~5_z,ey/eu0Yw2az*bo%Up'dy.\l$`v,d}6\r._u)iz0fy.Yw'ez0dz-]{-Ym!Ww3c|1`},^x.a}4[y.Vr'Wv,fy-f{0Vx._x*^u,Tq(Ww1Wu.Xx3Vo1Pm*Sl!Om%Zo&Hi'Mu(Zu/Xy0Ll#Wk"]}1Yt-^y/Wv,Pt,]y5`|.`:]y6l4d;\;c|6_;_}/^x'\v(Y{;`}6^z-b9`6f=`~8\t1fz*g3c~7f}1l4f>r7k9n>f{.mx?g}(d})[u-\r+f2`{*^|6a~7e@_-^x/\|7Xv0Hn&Mt.Wo,[x7Xr-[~0\w*f6o8l:k1}Gk>sBji>i+m~-hTn+b>Vo)Sh&Sn-Ss(Qm(Np+Ro+bu1by*hv"cd&eu1i~1p7iu.Xs-\v+[p bv%]p-Sk#K^FbOk#Xm'Pi%Um$ew'l{/es)Wx8Yv*aw.cx1[r0[v-\z4Yy1Ws&f5[z5`p8a|:Zo1`z7Yu/Zo)Uo"Mf#Ro'Yk"Pk)Qn2Kf$Mh!Nb!5V?e @[5RFf$Ka)M_'Mb(D`%J_!Ro2Oi0Ng&\o-Yn1`o&Nj*^u2Rm2|cоɳ[q=St=Pj/Pi-Xn3et@Yq;Xs5No2Ug.K_'Ma+O`-Qi*Jb&E`'@X.Bd-=[0;] AZ!Pf*I_&@\(B`"Ga%9^$Lk3Gj'Qe&Qi$I_#Ok)Bd,Ce0AY%Be,Gj/Dj2Oh1Ge/Hh/Pp3Of-Nj)Nd!Ii.Ge*Hg1Ea$Hi-Vr;Kh'Sr4Qp2Rf)Ph6Ln2Fb%Gf&De$?h0Mj/G`$Mc%K`E[I_E[!Gb&Da$Gj"Op1Lh/]v0Up5Vq.De)Nh,Vm.@[*Pi0Kh&Yr(Np(Uu8Ro2Vj,Wo0Xx1bv:Ql#Xn/Wr5Os-Pm,Or7Gk+;_-Kj0I_+Tu7Je%Hk(Pl,Sl'Yp0Pp5Ol+Po'Ie$Km(Ij$Fl%Ea#@b&Go+Mu,Bo*@_'Go)Rw:Jl*Hm,Dg+Su3Hk+Bd(<`&B_$B` D]Hm$Su4Tu2Eo$Fi!Tx7`z.Yz,e6`~0Z|4m~7l|4i|3Yt(Lh#Rs6]s,Tp,Mj,Mr(Sq+Yx3^u*Wr1Tr,T}>Ys)^x2dv+Rr*^y3Ut-Pw3Vs3[{5Jp2b|7^}3W{:edw1_u/a}5T{0Uu'^2Ps'Xv-Vi!Fa Lc$Ij,Lv5Ol$HeHXLh&Nr2If&Mo2Xv;]k=d}1d|.Ow.c5iz1ay.jy/f>`7];_z,c;bz6\x1`7k>dmj;f~+d3hx1g}9l3]}/as'Wl&`x3bv-c=ey-hy2ct)by0r?o;i1h:cAe4jGfb7c?g@jBe6^u2`|+m3j-m<}LyGl;s8m>u6m3eAmAp?xh?e};gG_=_|6k@a}3ew+m4b~=]w9Ys1Vt7e`=_|/]w+\y0`y0\l%Xp1Tt/d|.g{6]x,^{(Yp%Yu0]p,Ot'IjJj(Pl$Rm"Vn(Ts.Ur+^x+a}-Sv5Qx1^~)a{(`(f(cu*ao)Rp-Mi'Eb(Hg#M_Bbaq,Wo-fu,hy+by>eo=h=d5d4g7d/`x/Zr-f|3f2Ys.\x1]u1d3d5\s/fy(]n,]q,Ur6Wl,Mp0Ol'Do,Ji)Pl)Lh'Tk)Ga&Le'\p,Nl,Om&Vm+Yf)Pk1Rk2Xi1av-\{>]v7Xt3gҿɲVh)\u8Np9ZNXs?_y1^x:\e-Xq.Xn(Sj,Uk8Xo8Si.Pb,R_*Wp5Ph!M]!Gd.Ti/Om8Me*A`%Qd$Si&Jf.Hf%Gj5GjBJg5Mk/Qk)Ha=Z#Xm6Ld/Hd#Ld)Tl/Qf(Pb"B[G]%Xj-Db Me(Pk.Ci)Fg(Sp-Xp2Og!Ob'Ce)F`9R@b,Xf&Ea%Uk'Og(Jj#Mg&Mj+Gd(Ic&Tl'CaRaIZEc(Kb ?\!Ha'F_+Gb!Je#Oi%Vi(L`(Mn6Xq.Ww7So*Tv4Zl*Xx2Gl%J_!Ke(>ZQk0Ni E\F]Lb(Ge(Ad&C^*Bb%Sh&OdXs*Gj#Rp#Nm/Wl+Gg'Li#Nn&Ii)Lh&Db"E^ Ac#@_#@d$DZDa$@YJl'DcDc%Eb'Mp2Hc!Ij(:["H`!Df"Kh$F^(Cd*Mj'Mm)Mo&Pi(Pv5Ij$Ym$Zh&Uk_x+Yy2]{2Sm'Pm)Rt-Pi&Rh$Yq6Pk+So+Jc!Ng%Rp-Xj,Og$Ja Wr+]|2Ur-]z/Vp,Kd"Ln0Zq%Wr%Vo,Ld%Vn+Mh'\m'Pl.Rj+Il,Zq3Ln.[v1Ts-Mn2Ol.Yv6Qf%Ww;^s6Ml,Me4Jo4Uq'Vn%Rr)Y~5Qs2_w0Wj.Qd/Oo1Vz5_x/[n(Wt-Jk)Me%Ki-Sl*Kn/Pq3Z{8Kl+Oc&Ri"d~3dy8Xt)Og!Og Ee"E]_s0\i$_s/Ro(Ld#Gg.Po&Xf%]s"Si RiHd#LbZs*Im+No,Rf \q(Ni"Rj!Nj!Jc Wt,Wu/_r(]t'Zg"^n)\o+Ri*Qk/Ys6Xl(PhKi*Yq-Yi'Zt.`t&_n(_p(p|(m2g5`{'j|,du.Yu.a:lj1k6uAg};X{9\y6h~4]x$v9g{0f6\|5^v0gy2r=fAnCc{3^s*j+q-k:n>l>t>]{0sfCmCwFu:oB_x4iu*^u+_z4Yz:^{;_y1Us)dr']s#iz5j|&g@m@m=v=i6f?t=s6ok1u={4n=z;r7s4u;t}4hz)Ys)er&[v&[p(cy<`l+`s,^r'[q$az/`}0dy2k6q3m>u5c|)g~/`u"i{,`z(`{4cm4c8kCrd{5`}7iz-^x.d~/]}=[{4Rl*bs,Wm+Op-Vu5To6[{9[v2Tj)h{;bv4e~l~3q5j}1{6o4~8n5s>i~7iAp>pAk;pBq?k9j~0mBo8m3f{8t@jEd{;ky5ex7as-dw0eo)Rx4_u=c~5Zl&^s*f{1hy.VcUq%^x/Ul1Zu,f{1_t*d~-cy/^{.cu&Mr1`{2`z7e}2_s2iv$`y+at+g{3g}5\y6i5d{:by/j1oEcx:b~Ccz>dz?hϽdz^y;Xp6Xr;Ng-Ok2Ll2Jg)Vu[FYG`DZ>\ Lh$Fe$Ni!Wh%Ba$D_$F]Ad+Ji'G_'H_B^'Jf&Mm/Hb!C\Jd!Kd%Ia&D^#Tn$Hg#Hg&\z9Ld$Ij-@g->g3Ae$Ik*Qj#Dj%Gf"Gn(Db#6YG_!NgHcD^I[D\?`$Hi$Jc%Ae#Ok"Ni(C]=[Pq2Tz2Vv'Sl#Ok,a{2Ln.Qr/Qo-Xv.Lm*Mm&[u,Rj$Ll/Sm*\r,Mo6Ws.Pp*Vu+]{;]v,Vv1Xu:`y0og4d9e6m5d9i9h3u@m;f*h0j4`{-c~,c~4k>i9h3i-x:q:jAq>h=wBc0m>aupD{FuBtCvBp:n9j>i9d6Z}3]|4g9oKs<4h=j;sBs:o>p@sBi=ay+]t(_v'iv*On%lAjv0e:h:g1_y/d}.h7i9cz,]z-Vz2d7Xv0b}@Ys+bx3e{:av-l;`2j/g2[z4c?c}:l@e@`z6c~yEo9jDm:t7}@g:i8o5iCp>tCl6h~2q5d5r;vBsDm;rm;p9m3m1k9m<{Dr:}8t6qCv:m9o=g3ax0cz+d4^{+Ri*Mj-az1`}5kk5`u,Yq-i6h9e3kRp3Sk4Y|CY{=Vp:]{:Wu5Ba+Jm0Lp7St3Wl,Sg%Tu8Ww1\y<]{D`>Tw:Ry;Rq3Ej7Oo.Ab'Jh+Gb'Gf)Fm6Mn4Kk5Kg+Ii,Hd"Op3Mq/Li.Oo0\w0Wp3Mg/Mg,@c%3_*Ku1Rs:Po*Vj'Id"Cb#@V7]'@_%Nl,Fe)B_Qr/Le!Gf(Mi+:_(:^%<\Dk/=]A^Ba#?^"P0N.R1SJf(?_$=b'<\/V#=d*;X&3X2a(:[>b,>_&?b)C\#=^8_"2^>^ Fc!Di2<`$6Y9S]"Eb$A]?`!@d=[Bc&?b+Cn-Ss+Q|FXr$Xu-Wv3Gi&Ok(Ns3Il/Hd$Fl+Mf"Lu0Gm,Tu,=i'Fl-@h)Jl-Xw2Vu0Fh.Cn'Nz0Ou0Ow/Rw3Fi'Jh+Kj,Lw5Tx9Vt.Sz?Vu5Jk0C`%@a%Sv1=h*Af.Ge&Pt2Jl*Lp%Zz-Nz0Oy6Gp.Ls3Fm0Ck,Gn/Ge'Da!Ke'Lj*=ZKm-Jt)Mr,[|8S{9c};b;c9X}:R>Sy9Ux:X~HPv9Z~>[x:V|:S}9Qw+Vy0Jn'Mm,Km+]o(]r(Sl(Il(Hi-Hi,Pm1Uz2Pu.Ur&Xv/[4j;q:j?j3Xx6Wv4kC]{?d|=d@d}=dv,i7^~6St.Sk%Xv,cy+Sr&Pv*b|2T}9St*Qv,Un%Wm%Tv2_t*]y1Zy=\x*Uw0Kj&Ro-j{e9lh/c{/\x+Vp)\y.\x/dy2f-kAf:fAn?eBb6_}7n:Y:W@_~>[v-\u.Yp'b;c{:b=b5\~1d5o:i=j3m@`4b3cn>b~-Yq!Ot&Vv-Mu0Ot(Pt+Sr(Xy/]z.Ux,Su'Nx,_y1[3]:\{-Xp)b{*^}'^{)c8d/f8n5q8w<{GtBuFnDjInSe=d9_~:e4o9_3\4r:j:c3eBi>fBj9lGh:ZA`;j4b4k=i9m8j;g-nBmFc6f/b.g9_|7X}4^;`6Z[jFsHrAiBvHp;k;g;a5j;l@s;e_@_Ce4^~4a}:c4mgAi:p;s?k=d:c=l6r>qJnAf6if3b~-v:v@k;sGy=sB?uLzBsKuBSvDy@qHk@neD^~9Fe-]q.dv2n~1i?g?mAo@pBm?j@`{:m9u@m@o?pCe5a?e9`|+[o0h4i~BpAqHr?qEq@gIj};_r1e?e?b{5sƵ]s6Si/BX)Qj4Vm0Wj1Rg9Yj*Ri-Zp.Ki/HZ(Pn.Gi2Ge5Gc%Vg%Sp2Ra,Xn5Rk)Ov?Wp0Sm5Pa&Jd)Li,Dg+Oi%Db/Ig/Rm5Om1Jm/Tp'Tr7Wr/Yu:Om0Sc0Xk5Ta+Pa1Qd+Rf Sl/D`"E_"Qr5Ie'Qi%Mf*Jb%BRHW@^"C\I_(A],D\&L\De':X=TC`$Jc'Fd)Jh)D^ G]%Rb(FQDY$DY<]%BW$@X%GT ;Q9R7U%*J6N#BPH_/On,Hh$@^#6O9Q6V#=X2PH`$?Z@\C\ Ic@[DX Ka#Ga$7V&;W =X2IBZ?] ?a*;X#=Y1KC\!Bd%Kf'If%F]Ng&Na"H]"Fd#Ia H` Mk)A[H[">Z"C["Jb+DXD` He$BYBZGc(Da&Kg$Rd#Wu.Oi!On"^>`o(Uk)Ni*Wj)>d,Dh-Nj(Pk(Le"Nm+Ps3Vq.Ll(Om*Nl#Rq&Il)Tl-Ie)Wp-Pn,Us7ay2Tr(Qn$Pe(Wk*Qg%Oh'La Hg%Yj RhFYG^jCt~0p4i;_z0Rr-_t)\v1r}/l4e}5d|1j~0cz2_w-`t.i?d~3[z4i4Rr-e}2e{6b|2\n,Tl&Vw/^x5[o,Zn)Xs1_w3^v/d{1gE^q(Ut2Og Us&Om!Xu&No&Sk%Ok)Xz3Sm,Tq-Ur)dv+_r1Wr/Ws1Nj)Sq,Oi#Rn'Mh$Eb$Gf$Nl(\j!]|3n3d|,i|)d3f:i>c5b{8b4k;e;a}*e{%Vp&_r(`v)jy/jy2dw+iu"aw'_y,]y3Xw5`y,_y9]=gy0d6m;h4f4jw*_r-d}mr@i}.k>u;f>e8s?q;y>u6t6pAp?jFn@h?k@i9x9k2s2}?o@s;c@l8i{,h}'a0`}0a|6`|:x9r4p@p;s9vBuHoA|@st=vi4u=q:o?j5`t2d~@e5`}9d=j;i5j@p9o>xAv~=x>wAu2~DvJ}AyBrFz?p:f6Yy-Uq1j:`Am@}ExDzJ{>wEs6A}P~Mt>sDpC{Ju4|8@u8sCs4f>sEk6k1m:j5_{9oAi|bq2fz1mt2gs1ly9nѽɳ^y;Wu8`}>]wHOg)Rm-Ki-Pe1Gb.Lb*_j%Rh1DY C`'D`*Pk4Jn9]v0Oi#K`#Rs8Jj'Og*[y3Xl.Zw1Sn7Le&Fi+G`!Mi!Ng&Kb#Ma"Oj,Mj*Sn'by8Xu5_o2Wo5Vl5D^)Sj6Tq+Mi'Rl)?["Ii,Gd&Id!He'Gh+H`(F_"G`"Gf%DaJg8C[#Oj*Hf*@UF\G]"Rg%Eb*Ei(LbIg#Nf&Ul-C\"8R>[$=_!?W.J0L4X6S6U .L@U#CZHb#?]*=\!@a#Dd%;R>[)Lj6Mg$Ii)Mo/Fj+Lj-Ml+Ce/0K"2O4P1UF`$:X<\#1Q,O-E6M >_&:UC\=T=W@ZBc&Ok)G]C_%DaDa#Qo'Po-Mf&Vs3Tt)Lo+Pm+bMTu-Uo*Sm(Lg"Wj#fv2Nt2Ou8OjSl']DLl(Sv/[x2Lm-Hk'Qm(Po5Im(Bj*Go*Ql(Rh+Kb#DcHiFd#Uu1Vr/Tl+Uo&Sp2]x4_|:Zu+Rr*Kl,Mi&Ig%Lu1Mm"Ls(Vx5cv3\>R}5Wv6Su3Hn-Vr$Ow=Hm(Rt;Rv+Vt1U6Km'Ps6Yx1Jq.]~;Sn$l7bv+Xx5Mr6Zy2Yt,Us3Im+Kk'e>b6c6a=d6e.]{/Zx,VymIf;d/`y1a1l~/g;f@j}:d@g0bx1b3Jr'LiWo)Xx/Vh*Om&\z1d{0Ur-Kn-Qn%[x8Om-Sm*Vq,^{2\p%Wu+Le Tn-Zu,Mh)St7Qo*e}+Y{,\|-_}1Tx5\v3]u,[y-`0[u&Mr2On(Hj*Wv2Xp2Yj'Yt,bx0h}0_<^}:Qw0_z2Vo'Yv-Sm$PiJj&Rs*Hj$Jh'Ji,Uw/Z9]z0j>f8j3_7c:f.b;`y1c6d3`x/]}4dy.j;j?g@uM|=d~=\v+_~7j=_?`?d1\y9iv9sBj6`:d@qm?q=nBy8o5oBs@g?s7p}2b}1p9p?s0uBDo>m0h=h?d3eq:n?k>ktBt4GsCpm;qBm@u>j7j0wB}C~LToEmdGl>p=pIr@u-g~.{x>l?h=f{.i}-f{*^s(Vs*]s/^x+d0q-Z~2e3lx.r5_~;e~3iy,k}/s1o3n-s>oUh(Si)If(Ea"?T$Pg+E`#Gh-Da,D]6N@X!A^%=V'?^$H[)Kd,Lh#Nd&M_5Oh%Ti+D] A]#G_!Ji)Hc%D['Nh.Ee*Ic'L\"F]#Rj-Fe+Bc$J[&CZB]E`"Gd&E[B^)Fb+FWA]F_>^!B`"G_ Id&Gm)@`)G]#Mf!>YH_"BcLm-Ec*Bd)Ik)GZE]"BY#D]>V?[$=O>\#C`%C[!M^Kg#Gj&He'Kf-Hd&Sm0Ig(Qh,Kc$^o0Mg)Pk,Lj.Rn'Mr,Tl$Om-Nk+Il)Nn,Ul0Od Xo'Mr0Us0^y-`@_z-_v3Tx5Rl+d}BQq0Ml+If$Xs+Gi&Xl+Pj(Pf'Rs3Tw6Qp.Qi'Mk"Hj#Gh(Fg$Qs3Rv;Xt/Xw.Z}8\z5`|4lA\|8g7aE[y:_w.c4\{,Pr%Ut+Mn,Mm3Lg%Mh%Xy6X|0Ro.Mi(Lk'Po$Of)Kl2Ni,Pl+Pu]zAjDUr1Zz4Zw3Yt0Qm%[v/\z4Xn)\t-_x;ez4c4Zy0^x6[{4Po(Zl*]r*`z3^s*^|4bx.Xt-Xt/d~8h=n;cy-Vs3Qu,dz3bw*c}8Pt*Xs*]y+Yn0Xm+]x;Wr3Oo0Ml'Xw;Zl/\t0Qs.Nm"Ut4Vw2]z._y1Uy-\z,b@dy-bz5a{/`~:c?W}:`;Wu5Yu)Yw1Xo'Qr*Pq/Ef#Om%Wn-Db"]~8Nq0Vs/]z9Vr4Zm/Qt-^{0e5m4`6b{2j]|2Yu.Ww0Yr)Wr+[r(Uw3\|/`v/`{2f2_-e5^|/_t2by1Yu(c:`|0qBnBcjIk9`u/n>rAd;d?`{=du2b5r~1o:q?m;~:oGl3f}7Yr-Lk(Kk)Li!Wq-Jf#No(Xs*e}2\z(Up'`w,d}@5z@t7v=l{@yGND~@}FRBtDmDlEi9r?r?oBn:r{=>U}UxGzKnMt=i;o?m<{Hg?h?{?uIw?r:i>oGH?x;vHwCsz1pGs~;s:u?o3q=g>p2|8s^#H^%Qf#?W!C`-B^)Me#Ke&Ka$@`!Kb%Mk+Gh(Bb+Je*Fi-A_ Ga#@Y$9X#BZJf+B_!Jj+Hm/Pk:Lg(Uq/Qo1Vq,Ph Kh(Id+Pn+Wu7Uu4Ba#Ri Me#Pk0]w8Cd)Wp6Og.Jm-Le'Ji+Dc,L`(G] 9L8T>TGe(Nb&Tf&Ql2Ln2Ij+Wr.Ug%Qm/Yy6Ks4Ji.Mw?Ms-On'Ny6Mn.Rx;Vl&Fi*Ws,Mo(Kt0Rs.aw-dBSz>Jh)Mu7Vs2Qj+Ot0Us5Qs(`v*Ii-Xs6`8^z1Yy2aw-[B[u-Sh&Rq,Hn0Ni+Ww=Nn,Pi'Qn/Yg-Vo-_u0Xv.g;\<_?_=_|3_x4^|3Vn-\x)Qt0Qw4Ou0_~9Pp+^s0Vw>E];]In:Uz5]}@Zx6dy1f;p9b}=`{3_{1a~4[r-Uu*Xt+_s*Nq*Jm*P{?Tz<]y8c@^v/j3^w,]w)o8k:d~?`}=Vv6[v4^9^3Wz3Vx3ZzARr-Zw3Xs6Om(f~3Xw/c|+]}4e~B\w0f<{U`x:l?^y4f}5Yw+e{0a7Uv,Pm!Yu*Qt,Sl%Pl%Vu/Wr,[t3Wv/b{=c3\z6_z:_t-Li%Sx-Ss.Ss%\x.^l*Z{0h?_1bz5P{3^};Us/\y1]t*aw3Ws4Yx.a{,qDeCu;kf}3ke~4p4vHxHs?s@n6\|5Vt8Yu'Wz,Xw*g?d7g6\u,gz2^|/u7t=sCsHjEn:gy2k~0g9m4r:u3{?ve9bs'_y*au-`:g4m1n;j>l:l})f4i8f7n:p?r5|@|:Bw@~Ht>r:l?|Aq?o7f|1um?n:uHtd8e:s@q8w?IxDkHq?y?tFvDi;vKw?sBs=n@oFl9t7x=o3oVCa":S @Z+D])D] 9O2S&Hc,4R)B]B\ Rh'Fc)A]"HYNa)Mi'Lg/MaIQH`#I`(Rl2Ll0Ge,Su@Wq5Xs1Zj)Nd&Fa%?V Ec.A^,Pi2Lh'Pi(Zn:Np.Nf'Nl-Ee*Jh8Tk,Uq/Kh'Gb+Oi,C[$Lf,Hc,Jd-Pk6Rn,J`(G^+Qd*Pg$Mh,Rd*eq/`i.Uu3e@fD]o5iDYSv;^z`|=\@i^};]|3aw,gy,cz6n2`;jPl(>d(Tk"]s([l)_y,Po7j;jAk=mElr;jCpElHn@r;g}+gAcy4g|2aH`BeBl=_};_{4`{4_|6Y{9Zs3b|d>h@qCt@v?vBs?ht@y=jEt=qAp@m.c:l3hDjDm;rArMoGv:tAb:l;i=p?w;u@s?b2pQ^?k0e:aw0e|3cy6Xv;^|<_~<]p.fy0dv)gy2]y3`x/Xt0Vx2e{1bx+az,bw(g|/_v/dx2d3l6i~9l3_|dy3Yp,\v-ft&bt'g|+e9i~7ey5jx&j0j~-e}2dx-jz+\m*dy3ix-l{1fp#Wn)`w.i|4lEo2v5m1o8j7a|,fy0e:Vs5`B[8n3o;i4i1p@o;nD`{?j4kz,\o-_q.at*k>hz9ax1du._u(Ri#Zk"Zr-Vo*Up2ct.`}?au-So'e{3Ys1l?j@e{7i|7e~7_v3Yr/Ol*`w5`{1e|/Vw>]v3Vv1Zw(Zo2Uj-[b$Vb(Li(Nf/Og(\q1c~;bp5em0gm)mѾƤPi:PxFRm.Lg4Sl0So.Od/B_)Ie.H`-?_)?V#Hf&Ea.HYKW(C`':Z#;W'9[*Ac#:R9U&Jd*BZ&Pl.Je&@Z%He)Jc,Fe"Ic(H]%Ca*Cj)Kh+Mj*Pi.Ph(Gd#If?U&B[&Cd+AS ?_"Eb":Z#Je)Fd*CUC[#Ha#Pl%Hg"Ll*Oh,Vu1Vi'Ul'Pn+Qy8Qm,Ro?Ok1Nl/N`'Nc'MbHa"Ii-Ug'Hc.Kk.[o/aw2\k(Hd+Wx;`y3Jk,Nk2Me.Un.Xq0aw2Pq6\s3Oo/d@c}8_?Wi,ez=ky3sFSr+^|9Vo5Se'Rn*Ym*\s%Hd'GoY{4`y+Vv3_{4g3cz3\w.Sr$Uz1b9f}0Rh+^|5e;W|0l:Y;dHdCc<`=i5m>fGmGkHm:d~:Zv:\~6Sx'Qw1Nk$Nk$Vv+Oj+Ns(Pi+Rc HfYv(Nk)Zu1Wr0\y7^z9]Aj0iCh>t]0c~1aw.c:dAan@`}:d:^:d([~0a}+d@g9g|;p9m>c:W}4_~?]y4^~9]@_}:`{5j@b2Y/i1iAh4k6oFpCn@k2c}2Z}+k5kBk5^2c2ji8f;b{0e}4[x.a6d3f;dv*h1a8]7a{,m5m2b<\;gB_/f}/j3c:`v*]u/b4Uy-_:`x2^x)W|6gw*h2U9m/T{-X}-`w+[q/`~5d}0`{-c{+dx0]{3[|7e4a~2u8g|/g:j9n3y5h7dz3t2p1{;u?j8n.vGr1e3m1k0Xx.Wn%Xt1^|?f?e{2i{*m9p@uHuG{Gv>c:i:n8l}1s7t@pCm7r?x>Au;v6l:eEf{9`|8iAc0Z/h}4`}8\w%b4e~.b~6Yx/X{2c,sg~1l9o.s~4p7gx1lCa>_6`|-d2\t'[q-[p&dx+cy+p1f{5_y#j-s7p1l0ey.o:r8h4\s.j5m|2l1n@~8q?i3f0_*k2[x/dz2]s(fw.at)av0ey.bx0ez,_u,dq)^r2Yp.Xr-Sy,`{'Zu+`/g7i1^x4Vt-Yp4Wj+^x.i*e7fo"i8^p1Mi&^r.`q#Pl!i~6c}8es2dx6_u1Qm-_r+c|/Wl YpXr#Uw-^o(Ul+\{,f}._y/n3f~[ Om+Kk/Gf+Fl1G`"7P;R"=R[!F`&BZ%DRG^%;] ?\(Jd$H`%9S"I]!C`"Jf-Lb%G] ?^!Jh/Ed0Od'E^%Sh,He&No+Pk%]z4Mm$Hc(Qk-B_)BZGa&Fb(Mf&Gg%Jj2Je.Jb0Jh,Qf)Kf(Oi'Jk.Si"Kc-Te'\l.Sk)Yq,Xz9^q,d>d{/]v/i=d}9lIa~9\x1Xn5[y2Sj(f7Vx:d{9Zo*Nm0Xv1BZ"Nl+Ro-Om+Rl*Uj+Oh*Op4Ww7Ol(Bj&Ek,Be,Jj/Li'Ie,Ik+Fm1Ip1Jh#C`%C`$Fj+Mi(Ic+Qk';] @k(Be#Fe+[u6Si,Mj5Ju3Kj'Fd$Cl.C`";R9QLg-Rl+Nh)Ov9Y};Pz:Ou+^v/Ov1Jq.Lo'Ny0Jm.Iv4Rv)b7f>c9rWd8dEYH_CT9g=a}.b}9hx.`2O|4Zz5Lr*Os*Jn&U|/S{6Py7\x:Ln.Z{.X{2Pp&Zy?_}/e:b:\w0Qs.Yv1Yv/`y-Z|5Ql,\y9ay8Yu7b|6a}3b~?h}2`q)cw,\r0\u4Zy2^{/j8[8d=i9m0g}5Z{0d6Y:h~6m?_}2kE^6_7^y3Xz7e9]|6Zv-d5eg2i/b1j5g;[t5^u6eA\w8b:i>dCcz4i}0]}0[}4a{3oKe}5f~1g:a}*g/kGd6`;[~5d@eq3i4vAjc?g8nIe)Gc+Mg,Fi1Hb"D`'Ie-Hk-Hh6Qn5Ch2Ee,Pi-Wp+Sv2ZyXs3a|AgAf@mBaw4^{9e~5Yu'Mq4PthDeAdw6br1h>`y/f;dw,cy6_z0[u)Up.m5j~/e}=c=Vy0Ww/\x5Xt/`}9f3a=Sr)Yn&b}3e0`|4`Be}0b;a}1\{=eDk@lAnCi:lDa=kE_~8Xu'_t._}Ah>Yw1b>`z-by-]s*e|=`z2Zz>^8\}2Nm*_x*Un%Vu.^|/d~@iB]?X|/d6a.Z.`}0_u-d{0h}6Ms1^}6Y3l/_1]z*j2\{:^y8ay5f|1d0Sw9Xv1Lf#Kc Sh)Le Ke&Ss.Rx0a7\~]@b~9m<`x3]y/^w-]r.`w+k9_6a~1`}9ja;iGk:rJg?mCiIr>lFpCzAtLxDGxFpDi8]Af9l@j;eBdv/_|9Z~8cy2`2a9m>g>lLxd})g;o:i]u.Uq(h;l}0f}4k{3e{=Ry7^z:Uk#Rj&Tm&Pm&`s&s]*D_'Ic(D`&Hd&Hb+If+Hg4Nf*Ee,Fa"E`)9SC[ AZ"Ie,Ad1Fd*Fg'Qi&Sp.Vv8[v0_q1Vi5Tp8Vu8Oo1Jn(F` A^%Nb#Mh#Lj)He-Of+Jc&MgLk'I_%Mb+Fc)Mf+7S!:_%Ca)Lb&Ta$Si4Rq:^t2Wz@\{eA]|.Y<\{8Y|=_>e=o8iHmAu>uHrAlKlqLj;jZg;hBcCWt6Yv1c;^y3_{.[v.Vf,Yz0du/Xy;d;cy.c6_z6c~8ay/\o(^q1cw-]u*[z-c}3Xz5Yr*k3dw2[w.[m*g~7^l(^w,[r)av.eu3ct)Xr.Tp0Zs%\|7f4Wv*_v1e}1W{9Zy0`yg@j8i2k2h7`.`z2_}5c7^~6c=e7oBjBhAi;h=`3\Ah:]@c;Z|3Rx1Vu.]u:Ur+[w.W9\|2`r%d{)o@q~-h:Uu-Pv.`}8b~8i}-^z2_y9\x<`r'Vu.Tw)[{2]~?_rAs>{>vCi7hBd,Ok9Ql=Rs5Ur8Jo8Sq=Op0Op7Oj-Hh1Rl0Rp3Po2PxKPq?Qp(6Y!=Z)Fb-?W2X&:V;a"Bc'>Z(8T!6Y ?`!=_3Y*?a"D_%:Z#9[#@\)-V"5U*Kg(Bb%2T<^,Be,Jk&Cd&Jm4D`)Ck6>^*Lf+=h,Ij1Ml,Mo.El'Ec+Ac!Gf*Lg'Qq-Dd&Hf'Ki&Am1Eg/F]"Le-Qd&Dd'Lj0If*Tk,Id$Lf+Nf!Bd'Ji0Mj,Sn0Lo/Fe/Mk0Jp>Ni*Ml-Dn.Mh%Sp1Em(Ni+Hg3Lr2Gn4Om6Rp1Sn-@_(Ol1Gj+Hk+QvYA^F`=kCa>cCZt0Pg(_v,^y=_}=_;`|;^DKq*Li(Mh%Dh&Eh Lm5Vx>X5b>a1\{0`@gAWx;Pv-Os(Go'Ei'Rp'Xu0_w/Qz3`~d?rAh|6\t6a9ZE[x6d@vBkBmCfHaD^I]}=c8b:k?ay3Xz:gCax5[v8Wr>Wr9M]%Pc%Zl4Re&J_(Oi(^t5]y3Vr$\y,Zv,^u,c};Rq-Rq4d{6eAd;Vv,]{*\q,`z/`x.\v:]{8Xs)Ku'Rw2Om&Nl-Ni(^y5Uw6X{;Tq*\{-Sl&Wu&\s-Xr,b4\<_u2Z3e:c/Xu1Xu.Yw+Nk(Ns8Sv5`}.Zy.d}.]~7Ty*\w-a~/\;X{1[6Xx*Jp+Sz.bZ~<]~=Xs.[7e6e6eCh:f5ab5e>\~:c9];`B`{2`=\8d6dB]GhCl9e@`?Vy1Zx/[{.\>X~=[v1Yp$X~6Lt0Zu-Mp+U:U{=Qy=Ru9]@]G]?Xv+Xv)]y2Zy8Qv0Ux3Vw1`x,g1^},b|/`~4h}8eGiIoOh=_FvK|RqJi?iCnJdIb@eJfHjBmDkCpDd@]|,kd1e9e8^@jAh}=e;hDi;j=vDs@q:n:a~0c~?r@bz2h~-f7j5o>[z_|7j3_@[y-i-Qs3^BgBc8a=jGg6c1]y3_x,Wr1c;j_z;c~0\y1^|>`z6^{:]w?Tw0X|:X:c=bARx4Zv-Ys,Pu:Qj([x0Vo0Nl)Ut/Zy7Si'Xp0[o,Yv0Z~@bF[u+^|,Qn*f>^v.^~8Lu9Om'Ws,g@h|:[u0^s$\n&Oo(Zz4Um0]o.[x)du-_m$Yl3^n4ev?a}Ai~?hw+f~1c|1gy1m7Xo/]s+_u0]k*Nm%d~0m9o>nA`|/m>je>bAd@mCsC]Be>d|9`x.]x/h}.e9eBc@`Ca}?dAnGhBh7uBi~3rCrIhFk:i=o9k=p9sHoEgAkBlBul9i5iDp7h2jPm$Gj/Lt0Lh!X{=Vq1Sv2]y3Vt2My9Kr*Ms/Ox6TwD]z2Rt2Rp0^Cd?Ww'Op0^?aA`<_@\;^?T9Wy,cj1i9oDsGmCd:d@l;b4Xv,Wn'[l-i6iBSm.\|;Mo:Vz336 G@\c&If%Xu7Vu-P}@\{1R}5^}:f>j5f?Uv(Fj+Ww.a|/_2Su)Yr%Sn&Nn-Wx1V}3Zu&Po'\w+e+Zv+Wr&Ry6Hl4Cj2Wm+Zx.Z.\s*Ys0]j#^m"a3^y-Xx1`u%Yt&cz+j:X{6_=_}2e~4k3i=k7dAtCmAY=\1]~.a1kBk7b0g4n:f5k:jA_BVu-\x+`~/Wz9b1a5];\>d;Xx1[r*_9Lw6Mr-ali4d4c:c2c9i9{Dn=d:t?tqBw@l4e;t@sCrHkCi@hAb+i=v;x:kDsDpRL}FxDrGqDc9iAsRi=kFmDvGvGnNpFuPhFeH\8j3|?\}-k?fGdIvJrAvKp@xClCvi;w>uFK|@>wFM\WGGV]TQR}N~LNK|P}GuBuB}BrA}GlGj?lErCj3uCl?m>jCkAvAvB\>h?nj5m>d3c9d.d<_v6Yu+b~7Wy6f}-d.f9^z'gz3i6`|-Xw2_|1Ns)Ln"Vu$Tp$Lk(Pg$Kp._u0Wz:Mw*^{)Ov(Tj$Me A`#Vo*Ne6@g&Lr)\o'_v+Xi \p)\x(Fg&Pr0Hn(Ej$Nq&Kj"Rq'Tk!IjCi$Mn/De'?f[y.Zr+\p'Qj%De&D^!2MGaJk!Lt/_u*cEZm+Yw-Qw1Vl0Fk+Ea >]FbG`7XL^Ha#Lf$U{(Vu,Ro(Xl/FdAe(KjMm0Tm*Ng!B`'Fa*D_ Hb&Lg$Jc%>c'Ii&Km5Lk6Nf-Ql+kϺQTk6Om2Vs1Pg.Pg0Sd&Vd0Rf&JX#Oe0G`*IY.Nb(Ge+Sh2Ne&C]&Qm9Ha*Fi*L_%Kd0?`'Ug&Kb G\ Hb'Hk4H_!Ii/Fe)Lh%Jf,@U%;T!.Q":X"3L0Q$8U:O.S1Q5Q">[@_*Fg(Fk=Kk1:O(Oe&Id,Pd&Ha&Mj;Ld,Ql,\s0Uk*Up(Lm1Sq0Om.Sp:>[$D`$Ph'Uh'Xl'Kd&Uo&To-Su8hB^~9_t,\s/eu(Ri&Yr*Uu7Uw:Wp.Sm0Zm'Xl*Ni.Pn/Uu-Cd-Lg)Ph3Xx1e-\x0Or5Uv6Np8Nt=Gk1Kd1Rl)Lh,Da"Jk2Io.Qv6Ww:WxAZ{=R{>Iq.Om/Kb-Nk,Bf(Lo1Pr3Ss9\{-W|6b6\v7\yZ~A_z:`3]8_0]z1Zu1dz(]u*[{/Lq-Pv7c6Wy2dw2\p&Il'Km+UuQx,Ro'Ph*Wu:Xu,Ws'a|=Os/`x/_u'_z2Yv.j|3au6d6_u/_{+\u+[u+_7a}5[|7]u)Zu5]|4Ut)Zv+Tt-e{3cx1cd}:_};]z/Tr-\0f7]y/]{4Zy/Mj1`},Yw.Mu0Rv2Wv/Tv-]r,Zk&`@au,e6e@e}4pEk}5h}/b6[w*^v)h/q;k=h7f>p?u6]v2c0^3`:]:[x,`|:bh?k@i@b}:p7oEvHsBnGg?sFoEp9tkEg}@c}t>vFuMvDv@tpKz@oCu=o2vCjEkCl=iEp?v=c{'h|+j;i6i|7j}9mBn7h3a0`z/f8k/m~._z6Ws0cw9c~=e4\/e.ju.dy0Zy)Xu0Wq/Sk+_3m}(d0^y(_u.]x*mGa|:`4k2e8eGk/[x,c}4Yt1Ux5Yt0Xt'R{7Rw:Rr4Le"Rl)Jj&Kl(Ns+Oj G`#AYH`Dc FW!9OG`"H^FbGcNj(Ob*C^'I\"Gi+Rd#Mi(?bL_K`"OfRp-Lb#Da#K]"N`RnCQGY@QA_#D^"6S!Bb#Fb!>XCaATBWO`[o+Mf/`s0Sk.`n)Zl'HeLeMc#@` Ol)Mj*Gn(Uo!I`Fe(5]$A^!Ol%@e(H^=V>WJ^$Dc"De!IdF`&^p%Lo*Fi$F` Gb M`$?OKb#J^A]&Lk.Og)L`)Ma'Vf([l.Ke.Nh-Zm/lиR[s3Rg*Oh*Kh(Li,Ml/Om4Qg+On+L^Dj%LX>R"Ld#[p9Oo=Qu>Wh'RkJk,Me&Mo:?\)Pi-Sd/Lg*Oh$Jg$Ih,Jj*Ha(Bd,Ei3Cd-Ec&Kk$Ef#Fc%Be)De,Ln4Jg-Cd!Di%Gd Qj#Ee%Ml0Np1Oi)Uo0Wr-Ol,Pv.Um)UuA]L\w7Sp-Uw>Wz9In'Rn(Qm(Or2Mn(Qs0Uo.Nr2Z}6\t0Ro%Ws'Qm!Yv,Vp)]u1b}/Ln(Sl&Od Wj#Ut+Gi'Ie"Lk,Ok-Nk&Li&C_ Kj&LaRr)Jl,Lo0Kk+>]$Pu4Ie%Nm*Cg/Lv?Gn3Hn+Ll-Hl'Rn(\~1_{0Nv1Ru2Mn3Rp6Vw1[p(X}:U~@Tw8Po)\}@Or-Ux.^;Sy4]:a>Uu-\z,`1[x1Yw3Uv.Ry3Y|?Uu7Xu4Tt2Sv0d~8^}-iBf:Qp)`z-]|6^~/`Be:fBh~1d~:h}7[ye._;c.m;e1o3jDh>a:a@oDr:iBo:dy0y?]|2]~/f0Wk+O_"[|AR|1Ms#Vu+Rv)Ty4a|2\|1\}9_2f4j;j2b{0\3]w*\x7[y5h>h1j4o>o8b6c@^|2_~5ax-`v!]9X{0]~-Zz2\}5]}5R}4Wv3cd}iLs@w=iClAp;W~3`~4h:fy5ey2i6f9e>kCg?s4r;g?`9g;a9f=c1r;jEg;Z<^~6X{=Tq-a})[}(]y&i;`+`|-e-b};g~1k~8q+p2k/q8j9s7qIsBj]%;b-7`%7Y$6U'FX#:S"DSIZE[&;^-@e&Kk+Pe4Ij)@l-Lf)B\)Nn0Ip.Ml-Il0Lk0>a%Cd'Dd06^%Dh*Ik/Gn-<_#A_#@k)9XCa$Hd"@f$Ge'>_'Dg*Ij1Ju;Ki-Gl/Nk9Mm7Jo7On&Gn0Qp,Nl,\y0E_+Mp0Kr1Ii+Ld'HaRk!Nn0Tk-Ok.Ti)Qk1Nk(Ni!Jf'Uk)\x6Wu-Tp4Pk*To'Hh'Qr1Jm)Cg-Gk-Nr>Io(Ml*Lp)Iq-@b)Jm3[y6Rm*Tx>Jl+Im*>`,Jp+@d)Dj1Ij.Cd"Lp,Jl2Cl(Fj*?e'@a)Gn.Pp'Rm0Rp4Om'Jj1Pu*Nr0Ns2Ku5Kl*Sn)Sr.Gn*Mp3Ok.Pt/Mt0Uv9\~.Uw.`}5Ru6Vt)Nv7Hl-Sy;Xs-`|6Jr0Xr)[v3Vu-d|?]x:Wu-Yy6Rx0Px7[y0]x1g=\|4j2Rz2`~5Yt2[v.ax,Uw/Xr+ax0Sq/_;]fi;f6f4g;eMZH[Ee}5Z[z6Ko2Qy=[{_>oAnA`Wy-Y~,U8\St,e>a7Ww/_7REd>d@b=dsBp8j;m=hDsDl=h;nEp@_Da:c?k@ik=h;dEb}xAyMqDr8k9s;x=k=wCo6uDq9jh~7b4bz3i|4j?l` 8`,Uj)Jg+Hm0Ji2Ms8Ik+Qj-So2D`B_!:SDf*I]'Pg$SeE_BZe!Gh(Bd#Mp*Hhc|6mv;`:d=dt'Yz1dy+m-`v(e/iAX}5_7b7^|7`~9Z{0kBnoBo=dx._v,`y0_u(a}4Vp)]z3d/Zx.X{3]y-b=h2e>rt4i6j+i{2f9y;yCwuBuOx?PyMw?sAuBwKxDu@GwGvIQQIy?xB|H~DSJyKEzEv@GyCyOxIVLOBL|LrqDl?i@nArEkCu5tAn~0rBe4g:oDod8t;uCwBb~-gm8i@j@p5`}0h}2g/c}0p3mEmCt?pIi?k4e6l?\{3`y+_;f}3t5g~6iz1c>h;f}7a=c;\~Af|.q.ez*c7f|+m3a4d~*a2b,\z5kv(^{+n6m~-k5h;o381g?n}"p@e9m2^3d|3\r(Wj$aw#Xo d~(r-i1g,e8jr.ex0d4]z5Zw.Un&Rr'Vm \t$]y)]x-d9cr,[s/aw,_2Z|-_,`v,Ut+`w'Uu*]u)_q(a7Wp9Xk#\r,Sn*[v-Xp)c}&f~;\=c{8_|7g4_y(ds"Wo)Qs-Rm)Wr(^z+]o1Rm'Pk%Jg#Ji(Ke&Kg Qo+\p,Wl-Yl(Yz3i9Ym,Pr1fͶtDSr1Op5Po-Ri)IZ*C[(Gd(D^%Ok(Mc <_'E_-Nk3Os7Nd"Mk(Nn-Ge"Gg%Gj%Bk%Ml*Kg#Ih%Kf=h#?_&Ed#>`)Ge%>^"Aa=\">c*:Y%Ae$b4h7h0f{0b?a?j5f=`p:kBe7i9iChAn+a|%b}'p,h:m>i3s=nAn5r;iDuE:j?lAnFuHm1y4u9r>t:xIoIvEhFkr:wGsIuI~OFBFJyH|GLSLPHNJV`\KOOISKKGGG}GzCHy=MG|I{GwGEH@LF~?RHDSGxH|GyHyQrLuKxLv?xKIz>}?}Fu>uAvAvIuCnAxCfC\t,`~3a|)ax*vwCw.u=s8{LuBlAr?y=}=y<|Cx?CBzJyOp@vA}AjAoCf=`7r:p>l6g9poCk@i:l7`y.l6i9j=kAb}1j4f|5g.g~-e*i=l8m=n~*q1nDe5g5iCf5mApBs6p@p:|;h;f0b8a};e:c3f;g.h3d6c3m.f}2j5b8e=m3p2k=e@l0j:b~0n.`7mc$:\Dg$Ji'Mk)Sk)Un)E]:_+>\"Aa"?[De%Ae Gh'Di)Ih+Ce"?g(Fh Ed&Ee Fj&E]?\>d/m6fG\|/Z}+lJh~^9uAr>i5`3i6b<^>`0iAvCzFuKvJoBr6l:a9\x1]r*Xw,Zx9Ru,Mv1Y/Qw%Ox.[},g2a=dA^}4eDi5`|3c@h7h9f:a@c=W|1^9kDeBd;d|2^9i?kCiGcBoCl5l;d}-g3_w._{+[9Qv6Vs1Y~2ax+\v.]@\~5[},Ru*Yy.Vw*b|/dz._r'Tt)Zj cw+b.k8m7qGpBn?pIpGvAl@x=yHN=|GyMxCwDzHs@w?}B}CCM{HEHzHJAw<{AtCwAwIyz@FNPFPLLYBLDGDzMyDJCIP\YVLOQZNMRMYXQCC\XPNROQINBFGB~?{E<{DFxCEF}D~=IwB}RAH|K?AHMRVPLNLExKWRJEy=HwJzCuQuKi:~DFHxSvIxBzCF~IuGrIlBj4j=q5oAs9qGkGl>hMt7jCa3n8m|IwLwFpKl?sGmCu@lDm2vAiEi@i:t>tDuKx:xMvDuStLzKyGzFt@pCpB}PqAsBf>mC}NHzNyHyKv=xLtGnCyDu9x:yJQt?t=h?j;uBk>h?x>sLxMuDFp8g,o6zAo=eB``"JlLk'Fh&;X#=["E_-:Y"C^ E_Ej'CaGd%Gd-F`(Ng(Mm'Pl$Up,_m*Om;Le-Pi-Jj,Op1Nk+Mm)To#Ik)Ym&Sb$Pp0Fb!K] ?]Cf#?d'C^!<\Ke!@^$A_)Lj1Hf$Ns,Js/Bh)Fg&Gh(>e1?a(4^&=e"7f*Fo*Ej-Ek&Ab!El/=e0Ff0Bf,Tr,Df'Dk,E[!Db'9a2Qp;Fn:Hq1Pm4Pi$Ll,Og%Mj/Wr6j{7Sx;Mt6^8a4[}7Qs/Vw5Uv7Qw/Ij&Ig'Dj&Wl)^p)Zt,^EOx=XEg4Xu*Ou.\~:Tn)c}@\|4Zz5m@b6aEg}7SzANi-Zx4`HgTm@S|3_Ca2hy/i}<_>c?]x>h6j6iAj?i?bz(bx7c{1^?fe?d9_]v)]}:Uq'f9nDk?mGe@hEmv/$EnAv@|OqLsJvRtY}NyBvDmEsBu>rBnFqJPRMMONXSPXQFHMNWNYYTRRK~@]Y]P|NPUZGRN\OEI~QG}>v@nIsH|:z:SFBMUOGTJCJG};H`Z[US\QPZ\FTO]\IQ_i]bL\\XZQQGO;EP~DOLGBXGI|LRKSWLQH}FuDYMME?{HMIGxEyKPCo>xClFp?yNuItD{9~GiBm4uGJuFxLKxNBwHv?{Cj:sEsDf2l9k>xAv:r@>{JpIrMl@h/o=~DzEuJwA{GCtLm;m>u5~I}FtDv=xGDP{CtKwNuJmAzPQ}BLxZP}HvFmN~Kq@uCjI{GvJIxGGxJuGtB{EnCyGuFzCv?vD|CxP|H~HzFuMsJqDrPy:?}JuI=w=mNd};n@o=yCt5?~LLuF{?k[p([|1V{0]x+U@\}3_ud~9Xt.]t7Ll0Qk4Pk-Om+Zo+Vr/Vl*Sj)Yo-Zr.Vo/\q.Zp/[l/ex-b|2fr3`{=^z;oϵnPRy=Gi8Ul1_s0So7Ol.Vw9\{3Or5Mi(Jm2Nm(Vm&Ih&Ih-Mr&QeCd)Lm5Ws0Ro*Mp4Vt2Rn2Qq&>c)Bc(E`+Kd%Db'Ge#Tu+Zn&\z0Zz2Wo-R|@Tu8[}1Zr.Ns1Pv/Up,Mq1So0Ti+St+Xy7Qw5[|8a~?`@iBg2`;i@o=d|,Nu.Yzc@oIe@d7mf:k8b=j>gHn@k@j>i?Y~6gB\y4`}5jEj;f=tLe:el?i:j9t7{E@q=H8E@LGMFWRONIINQPCTFJEFzRLyD~Iy<|K~HyC{RO|QvH~LyEw>y?}Aw?oDHH>}ByqEvCn8mEwGvArW{=_>b~@Nu2Fm$Rv4_?Oz>Np7Qv2Np'Qp*Pv?\w.U|9Pq.Un0Sl3Tv4Z|8\r.Qs/]w2^?iHdB\}5Zx.Nv)St4Zn2\y;Qr/Ol(Qm2Hm'Tr'Jk#Qs+Mf&Ro1Uq-Us0F`(L_Ci.Jo2Yl(bs-Yn+[m'Tn(Ur4Pq*cx&\u*bx0Zy.g>h|3Fs4m7c~3k2e9j5i2uEhBkBzBe?qHjEiOr?vI_7R~>]:e=\x*e~4Xz5gx0h}>`M_|,iBbC[y1Xu/Xt:]x:QwrAjBlCnLo;r;eBcAp?f;k?tAq=tC}LzWHuJS{F~GD}SH~EnDqL{KzCFvMCG~BBtHPUXQLMPUY~LE}DLHGO[TbNVQG}KtBw8oGp?{?PZIZUXRQUTadTNR[HbQ_MNSNQLO^[YLSHRMSHM\Y_Y\TFYNGJKTKTLCF}CzGK:I=HRIj?m@vEm=w7k?t=tGoEu@q>hEkArIvCl/b?`0t@~H:m;r2v9s@pJF|G~WyXR}H|HyIv>~MuWxC{LvHxKrFjFm7vDx8yJuFx?uC|AyDoJs?u>oF`IjGp@u9md}8hz4`BiPw5ay+On(PeJd#Pl&Tv&Si'Rp1\q+Vr.Rq(Wu%bq'Pr1Id'Nh&Ea(Ol+Oi(Pr*Vk#Gd+Vt7Jd,Pk0Qk+Ok-Vm-Tm"_q(Us/bu0Xy6`o0_o,Rn*Yq&b{0ew.[s4bv.^q4Ss5Om/Y~@Zp,dq*Tl(Zp+Qt(]~.^w1Uz?\z9Xm$fy1`v1Nh+Ui%On)Ib'If$L_Sh$Rh$K^ Ld#Vj)On,Lh5Mh-Nf.Mf)Oj+Mg,^t4Qo(Nl2Yn1jͷ=o~?_u0Zs3L`+Pl05LAX$Fh3Cd0Vj2Md.Fa(Mj)Km5Lm-Wp9Wm/Sr6Rs1Sp:[o2Ut6Lo3Tr,Qm)Uu2Kj.Zy6[n(Tk%Kd$Pk,Oi+Ji)Pi&Qk'Pm/^t+Mj*Mg#Ni!Hf+D^%Ni.Mh*Pm&Sp+Il(Ki*Mi"Po.Sk&Lr1Qr6Qm)Mp4Pr:Pt-Pr6Uu.Su.S|A\p0_{7Wt2Kp2Tw3NsX}?WyGXu(Lq2Pu3Qu,Ru-Lu.Su6Il3Ru;Sp/Pk(Ju5Qw=Wt0\z<_z.^u4`w4]y;W|/Ry8Ur4Tu1Uv2Ln-Vz4\x.Xv.h7q6fz1a8jw+h:qBe>jv9rIu@q:p?u;qA}Dt5m?tBtCl>uGy=b/k>zIx<|rHrq?s=nAqCt3n=n5t?z=xBxImNv>jDe;h:f:oApFm;kDrDu/q3]/l5jCvm=i.jDiEhDeAjDe|9]x,_|6a{9Yw6d~2eCd;j3mA}@o~?Gs?ex:`y,r>j?hHo/Mq2Qu8_|/Ko,Z|=Is2Hp3Ik+Pr6Qx8Y|6Lm+Op2Lq2Mw6Wy7Vr3X}4Y{4Rw@Gp6Tu.R|CKu8WAPx1Ny3Wx4Oy?d>\?VEeB];_Hb~;^}=aKb5c7kH`~?\>]5^y5`@`;\s4[x1K_Rn3Pc$b~;]s0i{2m4mBgBeClGXy+`?]z6f-h;T{4Vx/Sv+Oy?Rw4b>b}5]y4g?`~4`{;cFi@lAwC{IrAnEm]mEtPsITxKN}LtOqMoS{JmFmFmFuHjKp>nGtJsDzErFrHxDgDiD[?jBuBn@lHdDeMdDeLhAd@fHkGoJlEmAqAo>c@mGmEhCi@kAd7_BW?]|4a?X6f/jCpKy]h@a.eBj?jBsLnDw?iBdAa;Z};j5f3iHsCmLeMgBlIgClKxLKNTQPyWzXKVP\c\[lDSVLdr\\]e\`R^W[TTXIg^]W`MZYY~OO|FLvMtH}MtDz>{GMNJZS\`ZU~p\UZT\PHKIQ\XXM\XYPXZ_T]WLQPPTS[UZVV^RSVXXPSSZQXNHa[X}L|GyGsCvA}Ho@oBr@|@MlEo:o;n?lIiEii@`4`De>`;]ysB`:Xu1l0c5d:i:hAg>]x0Z{4_w/_w/\v-Xm/]s/Yu5V|?cx'Ur'_s/d{0X|1a~=^v.]z8Oy;Pu+Pv;Uu4Hq0Rn([o+]v&dz7r9kDlCiAb}6Zx>l\Da|4_y1k5e~1dx0^}6Yv:WAUs,Pn([o,Ur2Tt.Ww.Sv:_C\}0`}2e2`m)Un)Ww4[y+Z}=Y?^r8b8k|2n=am-e~0_v1_{@Oo=Zq-Yp-Ym.Wo&Vl1Vu-[y+Ur4Ws1Wq0b};Ts7\p2Ii1Li8Qq4Xp5Ok7Ok1Mj0lͷ`q3Oh1<\+Ge$Lm6Fg3Of*F_+Ni1JR%D_'6U!Bg$>[!Af";^#Ec'B_Ci!Eg&9d':d#A^):`$A^#Ef"Me$Dc%Sk(`~>[t7Sr/Uq*Vo0Nm*Wm&To1Pp2Qs/Kk&Pk%Tm-To*Vo0Rn,Bg+Po-Ir@Rk$Pr/Mo2Qn0Vn,Yr8Su0\v8`}6`<\y:Uu/Ol.Sz8Sr-Nj*Kl-Hd.Cg(En1O{?U@Yz8`AZv>b~:^=Yv4Vy6Tp+Vr0b|8]|BVy=\;Zu+Y^Ca?RB]~5_Ba9St4g~6h?]v.^x1bE_E^BhHeDe7]|3]AbD];Z~;aAeAg;ZGlBb;l2iEr\w+\{6g@]Bj@mGm\}@f>e0f@m>]6^{1[};W~4`;hCl?_6jImGsOoHeFhDkIkOx@v=qAv8yLkElAj7r>o@sJuKpDs;iLlLsHxBxOxMxBzSuNwOrBs=uBv>x]~Y|QXUWTTOXR_QRVQLJ`TS\Y^eVPNQXSTLLZIVS\d\fVVFRC}FyJoJ~;MGF~BuLxU}T~EOyH}HDSEZ~PSZN}PyHz@yGGQLGCJxLKFJIKNNMJX[JaQ`P\`TUqsTOGRPS\ZLZHI}MxB~MwEs?iu@q:p5m>tE{C~A}A|<}BrBx?HQIGHPM~P~IrFzD;K~H{@|CJPN}|Lo@~BmHkJk:dFj?l6l>h@m;e3d=d=m;e}1b:b4l;c4[u._w;lEqEq@GzKuEvMvGkEoOyDlNj?m?vHj9ax1gAh@kAlNrKyCvEu;kY}/^z*du)l6n|.m6e~-i|-g}7i~=fv/ez,j~6ev*_u-k~+h4a0a~+_z.e:c?d~7dz*b0Zw/d{-^x0cv6Un$\r1Oq)]p.Sq,`}.Wn-_}2_q2g{1d{4_r(_z&a~4ny.py5k~+j8n5f8mBcy*\o'hx*Xj]m.jv/ft0e~7dw0Vm'`z3Zv9Oo2]o$e~/p9fBay4Vr/Ur.Xw1]r3Vu4Jn3_zcCWx:_Bj>kD_AnBvDsCmIiDsLlCr>o>dBTx+^Gf=^FkCnBg8]Em4dOn=d7`=l=o3mGi@rHnIpHvBcDnHtDd<`|Bl?m@sAyHqOvUnIvMqEGBNxNmFc|3e~GZz7f7_u<]x1\7[y1Ys'a}2[9Zy5S{;Yv8a{.gF_>cBb6iFc{LoEj:_CWv.d:Yy,b:m2e9n7pBj@xL>{DwH~D}@qGp@}Nz@wBK@M~IEx=~P\BWIX\\NQFKC?WXU_VJQABCKNQzIGJKF\LvFKAzEg5d9g{0bz/jCb~8n?yEByD{GxHo?kCtDyBvG~H{>y9u;l;nBjoDmDwGx8k:@rHu1r9p@x>m2g|3oBj5_;p7r>lB`}:k2Rm)\m"_q$]v'^u(Mk)Ts,Sm-Uo$Su&c6_w4Tx3`s+dp&k}4r1^~2bx2j8k5Z|8e6_q4[r5`q0e9`q&i9jAiz2cw3dv(Wy4Wt(dz)h8dz/d2k=_}?Y7f5l3e{,Zs6g7c=h{/j~9dq4^p4Vm)Ie!Nl&Rr*Lg(Yf*iu0Sk-[m)Yt+du/Zm+Kh*Rm(Nb+Yi,]l/]m+Rg+ak)`m+jγRl3Jk0Ro2Ro0Mi4Pm.Ni*Nk+@e4Ld-Qm7Io6Nm5Gj-Gk2Rj/Nk)Hk.Rs6Yu3Sj0Mn4Qn2Gh+Sq,Ki'Km%Hg&FrTv;Vt8[2Wt:W|BJv:R}B_}5i9g:_~6\|6`7V~9`~:Wz8bGf?]6\AZEa@Z}BVHUx6U{;U|3Ju9Px;O|Dd>c@]8YCdB^0i`?lLkKeBiIn?eEn?jHb6`8[w4Z};^|>_?i=f@ZEbaDg>mBcI`:jFcBeIfCiMo;h;hGbH^@hy9i7sGnCuLyKuLuDmDaLnFjL_GmG^~:aAZ:vFjj>iEkBcGjyM{Jn@iLsCo>`-q4z@y;wFxGyItG{Rv8Kt5Hq3Lg1Yt4Us7Wt3Vv9Pr9Vo7]z:^v.Wu:_z:Zr2c|?by5d~>Vz;Np:Qj@Sq2Qo/_}CXt4O{?Oy7Wz?Lp8Pm+Z{6Xr.dv0_y6[{6Zv2Vy:U{-Mu:Gl0Kp2Ii)Vs5[Pw;b?ZEUxTx6c~8a|;cFcEZz[}BRCb8VCd~?Tu7^>Z|:\C]Db@\~=bA\DoHhJfz>c:]@WxCdGjPvPuMdK_@hLhHgJs?nIi?lHpCqJm=lGaJf~;e}AoFoDhBj:hFjOiHpHpJrRpOuC]|ORL\^NGUoRzK|hRqOrNFfFeAfHn5k@{IwL{NP~a\wJWyJxJ~`TvWxN~N~LDPIvH{FFPEvSkAm?uR}OlKuSgCd:rC{HzGuCuB|FwFvI{P}LxJoDyHoJvP|LrGzFlHoMsOnIqDmM}XRlNqOjFqHv@l@nDpD~CyUM~\|OvXoFn>zRpIuKlF|KOuEnLqNrKxWvM|VW{W{SuPzJpOwJmOS{L{J{R{YwLvBzGhFrJdBc?l?h?yKzRQegGTPP`Nc]g\M\NOVab]U\]ZaM]RMIP]RW^MVVHYSc_POWMNMOMOLbJKJ[c]`_OMPUN_VRTTXe]i_KLeICC~GzK~RHLRLIQWP~GI{HHO~RPKJ~<}IvEmGv9s@=|iBuAj9i/lG~F|IyIG~IvBzG~C{8tA~CxLVzFS|DDB{M}FwO|BpBzBv@xE}=oHn=y>rgAo=|S|G|IlAmAoJxJdCu:n;m:es-b?eF`BmIeGj9lEl=oFq?|ElD]CmC^<]u7\x8f2kBh>dw7_r,c{2ay5d}:m?Wt8Wr4Vl*Wo1Pp:\y7Ov5a{1b~CVo3Pn-Rh(Yj'Ru8P}8Rg'b|4e8]y0`x/b>h=h@\=oOs?So;So;Up)Vy@jw3`CZ{d@dBnOr@wHoJvNwJD~>i?yJSLJOK}VK{H|FFrJ~N~LI{KnGpDFNzOZU_S{PXX~E{ROH~NK|PD~>uAvBxANLPMsIlJlJjDjCoAt=vFuDv@Ai:j@gDiCnMjHe@j=lFk@i5pNnKvQrKpCxRiCwIsLjQuUuOtQwHMOJrM~HKpDm@nBoFh=cqBtJSJsJv@u?i?m7jElCrDGMFZHM@BzK}J~EOJyTqK}Yqf2n;f4g9s7tDrA{I>{MuCvBBHJx@t@t;l;q5r0r=pE\}>yHl~.e2m:Xz:_|6e2i>iz?fy/_t*^z4]|4b}6k7n6q>i:d4e}/Xp*Yj-Tq,Uu6Kj&Tr1Nb%i0bt+Wu3Vr)^t$]j+j0`Cd<\x-qy0\v,ey0_}?a9\;Zq1No'Up)MfSj Nu5`|=eEl9b|7f8g}1n|(n2e~/j~0lNo0Tl/Tt:`v8]z9`x<\y4at4kʹn?Yy;W9S6Xu?X4]t1Wx8\9Vv9]s9[?^w8SGe3Rp1\y8cy5No/V~9Ry5[w>dVu6e?d?g~6a{7Sy6`y7d}TzJuPeFoBj@~]~OKzG}OxZuDjJdEdCpApHqHqFm:uDyHvLMrAvJ~BqBaBpLvD}SwRErEL|_}QoGzJsMwGyKx@sBwS|J|GzI|UMSV}]|ZY[aW[H{J|JxK}UxOPuzCq8kLkGj>n7l;w}Ds<}HG~@zC}L|>z/n}-iz(]-gz*au*`y7];ny8vFCs;s9k@^-d~0k4h;f6i0c0f3g~8l~;^~>^}8j7j>kBi0okIb1h;eSl+Xy2d{7gy*d}2Tv4d{1No+i|&d}+e~9`}5l0fx)e0jx,\|0Wx-]}4Vs.Sq!Nm#V~3Xt/Zz2[}3bw2k5qAf>l;o?f>eB^6ax3Zr/Ys$\0_y5Pr?`|9cz:nAa|4l~/m:b@bGmAjHlOq?iKp>_=_z/Y7X~@e9`JX|2dx6ey4Wy8\w?g}6SwAOr@[y;Wq8[t3Si%Su:Tz?a@n9q@p͵e}:Yy6Sv5Hm/]{D\x4Po8`x)Yu.Ry9]x5\x2]yGe?n?\:h?h?l3]x*jy*m1cv8b8Z}8_x,c~3hy0k?o?mPrFp;h3h|5f6h;]z:b}5S{;Up,^{8]z2gBix,jB`v:c1eEiCi@|DsG}Gp@gCmLlBj:kEg7Y|-a~7m;h7gGf>oDiAd~:h7c9ec@X9c9b7g:_~@`~8`{1d~Ad~6vAeCS~8_~/e~0Yz4Qu/]}4Vw%Y0d7r6h>h:d7iLmKh>gU`Gc>\~.mEnGy=pGy?8yHGMHIOnAuIoCzl7y;w>nItAoBq@rzR|NyEF@AwHzF}G@HK}FF~@zNzCtArEmHl<H@6@HvKu;iBlMk6v?OwFuByDLMtHuDt?|:uGyAtF|PDIGy<|7iEjAnIr@mDtOoNq9o>m:`BaDi?s2r>j4vdAyHo@iHu;s>q>x6q:b6]{7h.j4s@qBxf6tu@x;q=yPm,h1c2{8do0o8h}&p4t;r@p?3:y1uC{Hy???~=~=k>~?lCB|Cm;v3s>s?}N|O~FyAuD|@yHNzRx:s:v'm;l1x0v;n/d2n:k+d7m&r0v7f.a~2g>l?f=d3g5q7i|1v3z>t@wE|Gr-8w6n=e9b}2^Ag5d|'k1a|4a}6d8]x2m3f>m,p,d}.q1]}*a~.qAfv'[z)\u*cv#dz*\z&h]~j@d6c:hHa~;c:hGkNqOl?iBhEc;Vq4[xr@l=kEjFmDuG~I|Gt5tBlLjBgCc=l5f>nEr;p5o;x?nEqDe~<`7cDcEwF{OySwGpA~IwB|Q~PwIyKsAi?m<{ExFzTx[PySvHopCMzJ|NJRxDvTsHtLrCgEiApCc:a=_?oAiBiFj:iCcEkIj=k>h?iAzoAhGe=iJpCgBsFdCl;fbBpIvHlCjAgDe@e@kNbA_DeCq=dA_}3_CdAvBxHqALyNwG`;_GnHxC|M{CvBpFl;mHrDwIqFl?t@q:wAySe3d@mDjIh:wLjGt?t?t;lfz?kl/l8g{-a>h4s9m>s=p0w8d;f|1f~9l4N}8\y0`x4e|1iCxAs|@ew1`{9kDox9s9yGj?p/_6`z4Ov/^x2d}2]u+a}/\y,Yx1Yr-[q)Or6]r'c}-p3o;i~0c}0b:aw)du,cx.ay-_s%hz'js0m?m@iAjy5f|)hz/^u2\w)c}2\{;dz:b|:g?m9Uv(\~:a|0j5\u3dy7m6d}?]}3c{-d}>e~6h?k;l=m>m:^|-Sm,Ki$Th*Zi#]j(gk$x"_p)\u3cz'[n(]r'Rn0Wm6Tj(Lj6Od,Rn/Rr.bw5\n,Ok)Na'Tr0Rm0Sh&Sn+^u'Ri.Ok'C`'G]$Ol'Mc*Ec*De(Ld(;["Db"He)Ia%Ji3If-I^"Fg!F^!;^!A_&La&Md#K`'C^"Gb&C\ Lf%<`(Sg,Nk+Ni,Om8Qi*W}7Yo$Wm,Qq8Um.Ti(Wn2Xl/f{4am+Qp-Ot)au2So7_|=So/Sr0Qo0Pj+[p-Vo6Vj.Nl/Lf2Wh/Ui4Zk'\vAbs6vα_x3Oh,He5Op=XsCRu;So1Mp=Vp2Ur'_CRu;Ln.L~>\:Mr(Jq9Yy?Uv0U8R8Sr.Lv6Kz;Qx5Rt0Ns3Lr6Lk,Oj+W{:X{1Nr-Uu/Yv0Wr2Xw,Uq'Wp*Ty1\}2Z<\1[5W~8V{0dDbGl8e>O|7Ux@`+ZEW}1W~4d:]4b8d3i8l3Xv:Sx:j;d;`?c=d<`}9bBb9W{5Ty0d?b;Zx4b@]~9g2j:fAk9a@dHlD{:k:_H\D`@g<`JxRsAm@mGotB|EpNsHsLrGfBd@eClAmAt=oDrGsHhHjoDm>xGx;sEr7umJrKvPpQzB{@p?uMoPiErMjGoOzGry?l~3j8s*kh,h2]{*`/f3g;f@y@yGqGk>g:k;e;gl2c.e>e{0f?q=n6{It>l]~;c~0gw-Xv)`x._u.Z|9Np0Nc%Xw0Q;_@Ry5^9p9d}=b|8Zy*\p#Ww+Xv+Tq)Qr0Sq'St1aw)]q)Rn-Vy-j}2Xu+ay/h;[o.Pl-Op0Kh"Ko'Oq-Sz<_~-Ru4Eg#Pk$Ul#Vt,Gk&Sr*G]$Ib&@]#?`&Rm'=WBf @e)Hi/B`)Fd#I]B\Ty0Zu@Zs.Lg'Pi#Qp+Hj*Pe%Ng&\r*Wt0Sr5Rk/Zk#Nj0Lk+Op,Vl+[p3Ts9`y6m̲Lh6Jb8Xo.]x3Wp.Tq3Sx:R}EWu)Qr>_~;Pl.`}5\y3j9S~E[~5X~9Zk=gBtFqLo@n:r@hBk/m7h8r8cDj8k9n7c8jMq9qAn6k8p?p;e0f0g@o>lKv>s@qLxA|KyFxIyKs@q=nAyE~NRV}SoJuG~K~BHwML}VLPFRMKN}GFGJHXMLOIOyKINBOL}NHLBNnCxCqKvMm4qEoCuAoBn:l5`}-g4jDi6oB{BpCt8t3e4o5i>rAvDvD;}Bv0t@r/v?}8yCxB~?|RxJ>rAoAk;o;{5nGx:q@p=iHa>e9n=c6g;o>wl3o=w?k>^B`~8iFfDkFkBk=v6e=u=m?j3uuFln1f1y:j3u=n=y@y?r7l4si@yBj6{Iw8]_.]=d4jCeAoGeq?{DrIvHtLxNsB~ErC?}CzDtD}F~MySJ|Di@zOgIo=mJxOyEwNF}E|E~CvHyPmHxHtLnOOLNH{WPJ|UMMvB{JzBzAOU~ONON|LmKsQwL}K{NQaSxEQLJ|JzPCrNvEvLrL{DMyGz@x5sCf?`?eBm>pCpCyItJlFmFfNmFmDd?k8pEyBnIdcF_5_|:mLd>c5}de@`:^@Xw2gBh5i;Tv5Zy2bz1d5^9b>n?tBoDdFlEiq8oEsEj;`z9e?h@c7sb1Z0b.i\?_?`}1[~:\v(Ny=Vx0Ml#]s(_x.]y5Xu+Xv0g~5Zu/au%Lf Mg Fh*B\!Fb(Ij/Fj GjMn%Ph$Ph&Pi*Oq/Pf)Ln(Pu,Rw)Xy#Nk&He#;X$Eh'_w0]n0[y-Zp-Pp.Ml#Tk,dx-a8`q0Xy0Ju)\|+e}3cz.f^(6P6S#D_#Ri*C`!Qg*[u+Tu2Y{3Yy?Sy;_?Vt6Z}DWu9aDOv;U~D]E[|;[}:V;YB_ARy?^|BIo0Vt8Vw8[|iAnMoBkEnIfB^Ag3ax-g~3c?e@k=lAgCa@bBl4eAeNrSrQuJsBwDl@mCgMn=tP~OwPxFMRRXU}SRGUNWMxQ|UQONL|P|F{MS{KvZwSsG~MzOZSSKIzR{LO{CVzIVwWxHyPmEwB|C}IxFvCwJxPsOpP|BpBtElGpFvTtCzPI}KOx@{O{H{J|H~DI}FKBsCvPQ~W}MOxQzW|^MWP[OFHHY~UHWKVdgM_RPzJ}>nBzRTMYQ|Z~TNJQ|J|G~HzHvPxMyO{OtRyHPvHuEnBxKh;jEpHyCtHmB{HlH{IOtKpGq=lFmDpDgyDwJuDvBmFq:sAl7`nEgPbBlDcCf?i@[=aB_}8d>gEd};c}2_|.j9]?cAms:o@_?aDo4i*_:`v'Ts(^s+e3Zx2h;r?gIf9g6b?a:f1a}3_z6]=cz3du,Vr5Wu.`HUq1Vv3_=]t.a},j2jz2d.h;l3f4k+Z/`y2m;n@]{.]y7Xy3e}6i{-\|(i}+[y1]|1\x1`u-\|3i{*]s'Xu$ax,dy3dw'gt!hy,_x/Vk#e{.a,e@f9`v-kv,e8c{6[{.`|0]~-\z*Zi%az1m8p3e_,:_,C`'Ff.Dl+U4S@e%>c$Hg,Wq.Ur)Tp,Op+Ok+Sp(Yw5Uq1]{4W|0Z4Ow0`{9aw3Z}7WfBk9Tq4^F]~6d?`}@iEcCeA`5d9f}3f-j8`8c6mDfAh8ly)`}4^:f8e9r4l>`8m2\x7h?tAo?h9|>rDpCrFjMgOlIvGo?qBq?oGo:a7nAs:suAmEpAt@uJoG|LwFxC}EJ{Hn8k;^y.n;g:pBp>oG|G}BIHBJ~WQ~POxEHE|H{IzA{ZLH|JOHxJsAuPm?yFyP{JJRx\}PGxJQuSbS`{NyOxRrOwSvMvL{D~SE~GvTpFrQwE|M{NsAxKtCp9hPrEtIpEIq;nBzF{LwHxLyGpFyCBIyGwEwBUtFvGx?uDzEDxM|KyCC{HyMAxB|CxIv>n?u@|>=wBv8u:xDrDp>x@>r@x>{;}?@O}MGzGz@mLvIw@oLuGwHxEz@}IPHK|M{>s;MDwM}Hp;v?p?zFvKEy@xElFyCwCNOEaxN~KtQrEpCrDyEyBqCl?~IrBAzIrApIyDs?gClCu?v2w?n5rFxLnCuDvMs@uAyIo9nGi8v?v3jBp8r7p4sCg7ul>e4d;b8m7l;n?nAnl;j=w:k7g1l*eu'n@].\x2Xu-^>]|3c~+]:k5[x2[x,cv1_~3X|4[w&Vv+OdOkLq%b~8aw-ax.`5`z0^6\3Y4Yw+Yw3[v+]|/a}(]|+b9e8m;].Z~-_}/n3Yy/e9j|/]v)X{3a~1dCex+h}=b*ay&au9f|/gz%h~/_{'ax*^x+gu$i~1e.Rv+bz,Xx/bu)dv)g}-eu.[s.cx,^z)b.]w.\}1d{'bx.h/_s"h,j.l/mAnn}:az=hw0dw2cv.Zr-Gl Ro%Tw,[n'dw0ox([q(^o*Ys(Md(Uf&Pe&Tm._~:Vk.dy8p6z7};w>yIuEu@sBx:nCx5sDvBo?g|=r5rDp:h?k4o~+q?jq'qb!Kk(Cf&Qj)Kp2Pr)Nu0Z7Su2^~3eu5Mo5c8Yp'b}6i=_9c8]}(]}8`;c6d?[C[{9Ys4`u+Wy1k1f7c?i8W0^6S;Zz4[|7\8X{2[|<]?VB^:Z~6i?c=^@Y@jEhAdeAmCkDg?i8f6c5eAoi8mGwEx|KFKOQXLGzJHCUQWWIcK~JxTISUPLPUOXXOLPLOXGXSKbMKO~IFMQPXIPJLS\LyRP]{RKPL}Q`WRJ}EYLZQwYzMI{KrDqHlIs;i8`>bDl;}DHxE{L~JzPuFmOr@eAgGwxCtCvDwBu@uAw;wD}EpEr?tBrDtBw@p7w7j?q9_;c2b4_v-^}-e9_:f;iy,f8^4r;sAo;n?q@d?o@cGg?^y-g@pAf?m@i=jAlCd~/\z2^u+`r&`v%e}-_;`)g~'d+\w/_|*\y/_u&U{1Ys3Ol#Op'Kf"Yt.[t&]{(Uw(Yt!Tq)Ms*Wu&Ns(\y:Xt+\z-e,]~2]1^*]4]x0g.Ws,f4c:a:`8^4e-c|(Vw1`{/X{7i/d9k1`1h-g5k;i3p8e3`4^|8h~7a/m}1\}?fz*c~5`z,fx#]0g?g?t5i|-n:_{0m1p~+sUq,^y,a3_v/f4nw1a~/e9Wq.Uw3Kk)Oj+Jd*Ie+If)Vk'Ni(Rl&Ok+Ea@VE\Jf"OcOhRn&Uj-Tl'Gh'Kj(Wb Zr+Km+[q(Sy<_p1Zy.by;_w*b})Ty2Lj#Jh&Ml&Vu@`s)Xv%Mk/Rz.Kl(\s*Zn-Wo0[m'\s+Up$Pp%Sm+Vr$Us6Ql(Un'Zv/`~7fz&]|1Wv*Xn'So*`}3a~.`y/ay'Tu3Wv.Kd"Ji*Jh&Aa)Wl"`s&Hl&\t7Pp/Ul-Pe/]z1Ve+Gf*B[#Pi&Hn)Xu3Nm,Wq,Uq5Mo6Qh+Xn(Mg)If,Tj)Vq+`yXr8l<[x/`{1b~2^~+a:dBh?d@g:r9wEn/bz.h8iFh:b/bu'j|&`}/dp.f9p>iAp1mDlBs9pLtEnAyAj6i=q6pCqz:sAx>t?qA}Cy:tBr6}5CzFB~Bv6@}IyH~EF@u?pB|IIISTCIGA@D?DEDKTFJJ|B}M[|IGGwLz>~NPKuDK}@}Gy;qDrFuS{RqFC{M{^wV}JvL{OxS{C|EBwFy@oHx?vA|CQ{BKA~B|EJ{AxEzIMJzM~FGE~G~QyEDFKGJIOFJMSFEBCO]FIMQRJXXWTA^XST\UY\N]SSPk][WOHOa_ePd[SUwHLHBIzMY]KQGZIP}W|GH{=LwCwQ|LzAp9nIiFhPjKl?qCl>k:y@x?}@uEj@u?uFoC{<{EzCu3l0g=sCt9x>v=:q@r7u4n6wQ6M?R:ZH\Pg Oa$Qe GcJXRk&Mj*Us.Ym#Pv(Vq&Th,N]B^?SId&Nd"Ri.Kb'Qc'GYH\RcLaPaLdKf Mh%DVHZM^Nj#Kg(Lk$Nh Qn"Kl#Pf$RcVeWo$Qo)Pn&GaMe L[%L] U`Rd He&CVCaH^#Dj!Kc'Pg&Th*M^!]o$P_AYP]B]HXRe%Ga#L^'K[ DYG]#HaE_!Pg&Ym+Yd)Rh&K_!Q^"M`$d˯Fl,Lu:Mq*Kr3Tu0Gh)Hm-Eo7Dj0B^#Mk)Ii.K`$Fe"Ci39d @k(Go1Cr.:k$>o$@]:f5[:f*7c$Eg%Pt1Nr"Fs*Bh)Lp-En)Fj*Nm%GeCi(=k%Ch&@m'?d$Li(Mo&8b)Fe"@e On"B\?_>\+UA]>WAT?`%B_s_x(^z0No)[|*Mr,SmRmQy5Qo(Wu+Qv)\|(U3`8\5Ss+U{5W8[|1Rt-T}*f4Z5W7f0g~.h;_:a5nMmHoJ_Bgn5vEwDkBi>j~/gAmBg@n9n8n?mFuHmBg.s@d-j1j:pD_Io@V@k8i$o3k9i-k3m:n=r3l7d+g8a2p4n7qy+n~-r5e:m1m@j1uAwCc:as ]{(k/o9p/d?y7~>o/k@o9z8e3i0e.d2rr0kB`AbJlDx29r4|3cx(j/q0xBC9y:r?s5t3j2p1d1Zs*_|3e~4n3o{;hx/c|2`u*Xl%dw&Yx*fw&Yu&`u'Sm#Ps(Qv%_w)Yr#Vo"S_Rs(_v/f<`{6]z2_\y$]|*e1`<^{-Ty2Vn(Xs-Zo.Rp!NiWn#Nr'Pj'Km&Il.[x5Vw-]r(\s.\p%Yh!Ke$\r%Rm'Or1Vq-\p']x.\}7d;h?X|4]~0^3ar'ax%Sv0Js+Jk*Jl+Np/Zo1Of#Rp&Ih+Zh!\o Rr/Ws1Xs0Vs.^|1cv3^y/Tl,br(]f%dr/`z2Pk'Nk&Zp*Ys"Yo,Ul Kh%Lm'Ru0]j+Oo&Tj%Mi*]y0`t'c:Vr/Vv2_u1ap']p.Sq#Um*Qp/So.Hf.Uj.Tp/Vl']y0b|4dr7r̩Mp2Jr9Gmc Gi#Hn)>k)Ot0Bp5Kp,?e /UCg#7`Eb%Fh+Ep,Lq*Fn-Ls.Fk)Jj+Ko+Xq/T}:Oz0R{1Xv3Py1V}7Qw)Ux(Zy+Wr&W4`{-Xy@uAA=rByH~I~HR]~E}L}RNVsL}GPD9zMtG~QVJHG[DPSSPSLBXSgRv\wYNvO}]yGzIyStFiRvHsHtAmVmGp@rL}LPvJDQD{GzHzGS|NxOlErHiDzE|ItNGEuD|D}KkJo?uBu>{GzEv@v@c:`9j:hCjBlInBmAt=v>nG~Bw?nEdCfGe:jDchCm=v@yLrAuCgC_=T=W~6i4jMw9mR[|7qEkAsAnA`8r<`lqCjr:l;`1a2d2b~4o;l?h4`Z:e6^*_;[9^@g>qBg7k8aCk9au:rGr@d@[:s@r@w@n7tCs=v=z;}LzGp4w?xBu=sGpI}LGsBf9pCt@zDq=kAnFk?n1k;j~(f2^z.b=n}6g=f:d;k1a0o}5d3gz/f~5gAo:]?b6Xv7l6`)`3V{?bCg6i;r9m2h2c};]<\}:`x6f}.f3dx,]y+Qs&Gi#Dg*Mk"Vu0Yt.c/c@`A]|6Ux3^u0Wo/Qo0`t([p-Tg)Oj2Pl)Me+Op-d~?Rq'Zx(^o0[n+dw0Rx.^=Pt=Vv2Sw,h3g2d@^<`}8^{6bq4bv)Wx4Nn(Mk.Pl)Kq@Gh(Fl-Nk,Nm0Xs!Zt&bq(Pd%Hm,Oh*^r/Xy9Sr!Qz0as&\h'gr'dz3at0Vt@Op4Tr&Js1Rs/Vo;Od+Ls2Sy5Yx/d{3^5c6Wj/Xq7Qo0`x.ax6X}9Ts2e@flA`7dBmBy@zPwGpLqBoG{R~HyTyQ~KRf|Dx@MEPJ~W~J{I|LBHIKQOP]HKxL}@}JzGB~G~QJSPVYT^]}UOZM|M~H~I}LJMRKSRPSLF~I}WFPJ}I}LxNXQZEUQMVI~S~HOTOLL{SzY{Xb}QxIuN~QR{FrA{TIyD~R|R{R{Go?wII|InErB}G~C~ASNMAG[OX]MQLEENLUQKPSXMJE~QXVVKKIEHJMFXT`OODQQRNNQ\^MOUJxRsZ}OuI{IsHyBvGwHMzE{?yIzKuPtIuIyMxKvCxA~GGAGP|PxD}HH~HG~G~YSEJND{BsMf@wFv@iIuEyDqG}E}Gs>}IxHtJjDh>j:e8d:e1f7d2h4q.gFj7i6a6h4d5g.b2l2f1_~4j~8g9k:h-p=gBl;t=r+js/w9v:uDnH|Gy6?xA@vAo>i4`@_CgAv;|Bt5w=k=n=hJzSm1q@w;r<}CuCuHsAsGn@h?sHjCvFx@zp:w;r9l6i6b|)b3h,m5u9x4o=m=j:x=vDyG@f5szM5_~AWz,\t)bs'ex7^n%Su.bu.Vz5mAa|3^~5Xl+\x8gu1fDdzB_y6jy2^{2au1^s.[o2Xo4Mn4Um+Ri,_p-_x.[o%aj*er6Vr=bq*bv:Wy/^l%e{1hy(\z9`n#Uj%Wr5ev7f6p1m:^y3h}8lw3ft1g}0er/ay+_{/dt-x~,v@t?lDpGj:e~7e4k@z@k;qd-5Z*0_':c-/^,1c.7d,0Z(=_"<_ 5W$8e).]+>e+@c,P3W 8]#>l,8a 3Y"9a&>c+E`!Di-2c'Gq.:k/9c(=h)4d(8^%Go'0a*4\$5e8Ej->m2:b#2]":d"0c).\/e%6e3?p(5o5Ho.Gr1Gk+;i'=b'@g)3\0^!7g 9\ Fi*6]#4_#7WA]7e&4[Ad&Dj(Be)Cd':d#Cb?d 9b"Hn#Il)?c$Qh&Gm+Xx0dAVz2Sx.Xy)X?X[@hm:rIpBe9lInArDh9d@fG_@\9]1_{=`~1b~1WCTz4\{*Sx+S4\zC|ArBm?Rv?}HtG|Di0mHo;kCd:kCcAmHuGi:r=mJjBa?_0a6_1_5]>f~9Zz8Ww-V{8Tz/^0Y~9d5`=Ws)iz1Sy9Xx5^4d?_Bc~2ez.jx-Ur0V|6`2S}9Vv1bx*Ww4\n&Rk%i|&`{3Uu1Yt$`}-Tz4Yp.Wk,^r.Ps,Gl-Lo6Qm,Lh$Oi$Pj'Kd![m(g-On._t-Ps1[~5Z|3i7i:d9_|>boBmAk9j~9jMi9eCi3d5d-`6]{=ez2eATBa|:`>j6k?gA`Bd@^{3R}R$3N"B`&Gf+;_*f#Hi)Hj)Ae%8_$@b'9b!=e%9]";`&)Y:UA\"Fj3Ih%Bd'Cm,@i#Ip,Gp-Dc#:V#Hg$@`;[!6^!?d&>d"Pl-Gf%>b#E`#Ff&Dc&>a%@g,?[@c?`4R@d$Fn02V!5^#8Z&@^=b"D_!H^"E_J^ Jf(Oe*Q{1Lo"]|(`.i4\~9X}=dGnE_C`7e1fAc?d~:g~4T~B_Lc~@cy.f}3o8]>dGmCkLlIwQxSrI~IWv^VZ}]UM{dVSTyLmR}VT{HOBpAxNGMOHKIPzJFNvN~MJ}NxSyMWzKyLvNyHJRUTgcT[^SZ\_dn~[XV`_U]VV\cW\RMdc\YU[UQNxLMTVQ^gbVX\RQYW_UVM|TyQ~cF~PMX\\J|PQkPO\FRSTI_RY_M]SVyGTNTNWTLOL}NXH~@HzED~_Fu4oF9zHG{BzQNw=}GxH}=w:s=dChGfHhAi5h?pJsFqHvBp7mDiGwGtAuCtAt>o5tAuH|CEyHt?mDg@]?j?jAd=rG{:N|TwO|HoHtDrISPXSEKT~H{C{QwFzP}F|HvPwHy?yJrExGsO{@uEzQz=vP{OqHyByDu:GL}S}BqAxC};@ByE@|D{C}Rs@s=m;o;q8tFlHj=uHo@kGwBlA|GmGwBz>uDuGpCo?vA~CoFr@gCoAe?Z~CYy;i4dB_~8`~*e~)e}3c{+dC_}.Xy3Su3Xx!Yv+`{1`v,Qi'Ps*f|,Wr*^|/`8]z,\z3pBg9rHwAi7l6p5j*z6w?kId>j4m=m:l8ozEqGuAr>m>i>e>mpDgDa|0bx+i/f?i6d1^w.b8c}/a}(e~+]@Tr;]w?Vv9Ut0c9c|6\p,h8Oq.Ur(]q+jw*hBe;Z~3e~7eBev-jt(k~6a}6a}5\w2\q.Mi'Tn)LcK^#VeGa(Rm+V{4b<_}1]z0m3\v(b~0[};ds-^x1[j+Yp&]s1Og%LRNd Ih%Qk'Hj1Sm,Ri$RkOk#k{-f{0g@f?e3p},i7f=e1h~-c1m7j~0i3h3k~.r0q7t9r6l7i}-q3t1u5g~8^n.\p&Ld$Si%Vt2cz.X~9_{?_r4Wm,Zo.[n-_p/Zr0Xr3m{/o:i9]p)iz5j~?ox?o̤;Y68b-Hp69h36`-Ci04e.5[%-^,-`'0b&5a+^">[0_&Ao1;l3Fm:Hs5>o*?j+:l5=e&Cl-Ei&.]%@f/6d0Hb"9e"Dl#>l$8`&'\4`"Hu38k*Do&Aj%7a"5d)Fp.>` 7c'@l38[%Dc @b5^6`2Z<`6\.a#0`;h 3_ 5d'4_@c#?k.Ai&Cd$Jk"CjHv.Nv)Px&A_&Qw6\7T9W~0\{*_4_5Y6WB_Ih;Y?a,b7c7a{6]}>_v4jjFgDe@lBsVs=`:^6Y@^?g9ib>g?o6h?c;l;n1s@xGn;l.iMnKvCgFlGf@cBs:h:f?hsHqIpFiBuMsHu?|KhCi?gAm@f?k@pEk>e>`9cBf>h6q8e=e>[}3\|8b?g:d9h>lg=j5X>Qv0a{-bw-^{6\v1jBc3pBkDfMe=by/d{:e{3`7Y{2U{9Yu3\}8a7]w._z/cu.az*^z,Z}>T}5V~9l/Wr&a~+bv/g=f|:h=k}:i}/`6[v/i}3`5d8s@g@a{4]5]};Yt/i1j6Zz9g8d@^w,_|7Y|Af=j=jz4d@r?hf B`EaCj#El)Bj&@`&Dd$Ln%Po%Ws2Ws+P{7Ly2X{6M};Kt1=`%?`FcBb@c;b#Dg%Aj%9dHk)Gi.ChF\Km&3Z!A`!Dd*IhCd=WB\ >e$Rr-Sm7]y8]4a/\.\}/Sx-Yx7f}4j6i@pCn@p@{FuEv=n@|GoLn3lEi>n5i?mCmLiHkPs;t@p>l8zJuIpTyMsQwOVRHVP{G[wGxSsJqHO|PU{[fUYXYUZ[_]gQMZKS{LwNxNvROMRZR]dmUSUiddmZ_dSjd`afdhYNNJ|Mb]^c[bLzKzUPSR\RqJN~U~PxRsWv_u@iFlJ|E|CvKq;{IpLx;}Gr?sEn8mAuPrPnHuRyT{VTNXKMJCH}H}LyFwMwL}sEsCt=}?nGuFx5t:g@g@wLu@|@z<~GvKp.eEZ|=ZC`|.j:i~=hy:kDh2kElEqEeAr=zFts;k:o=l?iAjDg>g}7k>q?iAn7r9v?};xL}MzBzKC}Iy:nIf;{Ew?{N@Cs;@z@vCDlGzGI|AwJlGn?hsBsv@t/l?u8ey2b}6ar0]w9e4f@gt.`p(es/ms,r5ix/s9r+z5x@{Br?u;s9v;rAj~8o4i;y6qDzC{@u=t5J͏kBa(8a,Ek,>e*?[!Bi,2e*-X)3Z*;b.Gi'2W#0M9R Ki*Ml3Qm;Ji4]u3Wt&GW#0K2R .F6Q/S$;d-9Y%<`&Cc"8_"@^#=h3Fm*8a':h#?`:Y1\"=Ye!2]1]3\&Af)8\(Gi%?d&Gi"Cj!Af>c"Al$Cg);`#Km!Ku1W8Tv5b7Z7\y5_>fBw7vAyH|IxCyLrNrQ{LxB{1n?r?t?j8qNmGh;m+f)[y4dEj?o:hB{HM][MRpO}PyN[yHL~QOLLP^PWVNEJz>VTGzJzQzLqCuBiGmJrEr@R}LRuKHGGvD?DBMYJyEoMMOXOPMO}T{M|I{LRQ|EwDwQvLvHvDyMwE~HuDzFzyIz<}@z@vFeNe>uEo@f<~B{LxItMo>mFoDrKvHtBg;p?xEv@gEkEq=`Fkd}3a+nBg8b~-^*k{3hx.^x(h>r;k@g?p;p;p:xKwAn=nDj?g/u;oDs~F~D~?>zG}CF~5v8r5q:d1d|3}3}H?lFy?j:x3r@sEo>yLJ~M|Cr;kLrTuHqCz>n2s@a?ph=t@n8m8e~5q7p6e7\@j-w3hv,fu*i~5bv1l/j0v0w1v=y5m?qBt>wJ^z=g~6f{(ct*Xp0e{/]s.gy@o~0{>v/t@p(dz4}HLu@s7k6l4l7j;|?}9tDqIq3pDtFI={͔u\t6Gq4;p5Gj=Co6>d)Fd+Gl5Bd6:h?=d17a0:f7Gm-Mp+Um3Mo5Qs9Fuc+Lk+Di/Li/2\%Af26d(>d*8`+@^'8c.Ca0Cb"2X*_"Bf%Lj2Ko6Bd'Mp0Mm&Jp:Gj&U}:Ou2Jm6Gp0Mn+Cj)Dh+Bi+Ga"Lt4Dk)Kt/Ow7Sw/Sv,Nm(Mn*Kj&Gh'Lo-Oo&Lm%;`6X*;f&@i)Dn.` ?]"Ad/]u6U=[9Ru1X{7a>k=d}=h4k?eFp@h=dF]DfGkM]=jKe@iBmCrHyCpAf@mI`Cc>fH|NIuHxHyOyTZw]{LyZdW\c]P{Ya[]}U|T}R|TzIn@cDsHoL}LzExQByLr?~G}K~J{DyInDhGfHlB|KvQzPyItSuOEwIsH}TpPiJlMrGxDmEvDjBjOsCwJvR{NL}XuJuNzQoImGbHg>mb|<[z?j@[~>`|8nBb@^>cy1^|=f~?a|?tCp:m@ho4v@a}:g{3gt?cFh>l@i@eCe}8jy2d|-j6j9g>s?nFdDa@r=g?uNYiOsKrPtD}By=r5s9l/f~4t1:u=oB{:q=s;k?r?o;i?y@FuCp@sHnIf?k~8l?h~;l>tAzH~NKRpOrQqJlCvQtGeIfBxHtCzNtGwJpGlGr>b?cCsGgDu@kuB{AEZ}]H|N{ZzLPRX{DvOzJ}QN^Xw\Lm?f?oFlBzB|C|CyKxD~KtR{BsLtKoIp?lDl@mBu@rGnEtL~:v=u>|?x>nCmIny3qGqGjA?x8lGeDe6kCp@k?YBi=r=x:rElqDkCw:wDl?vGz6l4q|-e9hBtDw;I|@wAle"F^7]$>b$Es=Dn,Ef#Jn.El&9d$wDsG}Cv@vH{ExGxCE~Ko:nCf=cAnGmFqFtD}M|N~KTN\wIvDOZvNzLySlI}WxOxCuBtD{B{NrHnCr6m4m=m?t@sR~ZyMwJzKxBxJ~P]eQaWCGVQNK{ImXiBzFzOzUIvDvMwHuLuAsFuPwOx@uD{KuH|FuKvLvFvCyQ~=yFzJq@k0b3kEsi>mC_4f5b9rDn7l>k?d>j@j7e5g@b~.`}8c;a~/cy0j*f/o6j~5j.q0l4q:eBm:q?y@q;d9z1w@xCgw>nDnDvJqEq?pBl;jFoAs=qAsDm@i8l-h7sOyIq5o:g-j{'n,l0v;bz2~:r2u7k;o3ft-_s*m5i3p?k1k(nCw3km@m:h:k9u/uTm@jB_:k?k;i3c:\Hg:l?`Bg>m1p;sH}QI}UE~K~F|>yP|Dq>xIl6xu>s;y;x-x:m8_-u*`@o;h|0Sx(b;m|'m|)_y'a9l9`9a0d{/bw/d|#_x+_9l2j6`~4v>v;_?j6e=o7e;i8sGyFwI}P}MuQzItA}Jn=j?uCwDr;wGw<>AzKxIvG~E~DuFJoFzDM~MBM~G}JrFw;yDp@HGxKDzB~Ay;{@oH{JEM{AtBoCn7uB~BrDn=oFy>u@n8g;l6j@f1n>s+q7f}-a~:o>u@l{2a1k1d{5qKrAp8pArBszA}D?j4w:t:w@pB{HoKyAe5rCr=k6n:>|DzIv=uJvAo}Bj>xf%Af 9a&Cd%9f$El*Af!Ch)?e(?j/KgEj*:_*:\"?d(;^Ci&7g*3[6]%C`)0U!4]$2T 1f+@e'Ge*6a)?e&Dc?f,Hg'Ed%Gf)@f"Fc Eh$Hj'Pl,Gl%Fo+Ko/Gf";`'8`&EenQnFtGcCoEuBvM~Mu_zFJVT~[{GNVzC}LoJ~NRSWzJHyW{JyNBTzBOErFJKJNKMNG{FAvGqGo@pCv3H?EzFsI|ToL]vEx6oGmMPqOvOy@oAkmDgAm>x9a>tFkCx@o6p6d7f9oAtJmCbCeGqIkFoBCg6t@a9v7j8n?q@l~=i~=dz3b4cHp6f}/i7n@sAr@uEdBl;i.k:m9n=zTgFl>mHm8h5d6_~=j;uJi1tFnl|8d:k:o;nBrB=|9mAq?fx5c8s;|>uC{=wDq3v<};yFl?jJm9oCxtQzG}L{F|Bt:zCu4rSoEnHtCp9qFtDh@uJxEvExDBzMBnGDB|8g9sBm9e?\n:m:Z}6\x>Z~:_5d/a4u;`5i?b;b{5\u2k:e2i3h4l8c;h>i=f@k>k0p@^l9i0i;A{;o3DxL}Dn=o:tHpDrGyHoH~AsEuB{?{5uBo>ko7n4u:e?f?j=d=sAo6}s>oBvFj>lCkBi=rBj=u9h3nBo:n:r~/m3n~7`9`y?cs4ny6k~7m?k3m2dz+c6k2_z9g:p:uAn>m7i/n~1l}AkBly6eBu;q5Gd/^BmAx=rBtAvInOcyAm@p?ix4f~7r>nFmg&Bg#Fm*Ff'Cl$>e!Cg(Fg%Bg$Ai%=d#0`#8b"Ah-Df$;_#?f ;b Al$@e Bl2@h+:_Cf#Be"B]:`#Cb!@e-Ip6@e)=i'3ZEg'Gr,Fj#Mn%Dp*Fj$Mo&Cn'Om"Nw.Kq,Ft7R{3b7`-Sq(U~.Px&Qx*Km%Rt-Mv/Dm+W6P9Nw)P{+Qu$Lt&?m&Qw0Lv3Lv+Ro&Hj$Os(Gs,Dn+T~8Z?W?Lw4Q}2U~-N{3Jr+Iu-Lw,Ox(V~,Kw4Hi"Ll.Qv*In'U-Qq%Eq,Nx2Dp0Jw.Qn+Ko'OiJv*=l#Hw4Cp*Lo(Kn"A^Jm*Hm0QhHv-Hv%Pm'Dj&Qm$C\Bh$Sy*Ps&Rw&Sz-]?c6k;gi;n>s?wIr5i>f:o3|FzDvMzEFs?mAr;wHmQ|CeCp=mBy@kBoAvNbCoKvCk@tN{OwUa{F{NSIR\YUWMLPYcSVfGZNzH~NULWR}HxExBz?sl>jFxA}KrGuL|JvMoDs?uAoCvMt>vCuE}Ai@g@d:sMv:vArE}FNzNL~IzC}IeMhBsDh1n;pFwE|AlAuKrGr7r3s;l9e7d~>r?fAs@r7sAh6k5u;y9u?tJ}lOmDwBmDj@c6e@nIyGt6f?qJrJtCqBt9e4kBg>uKrFO>E|JsLjEyEzEuEwFl=p;n8~K~E}>v:zBz=n6x?}<@oE|ACxNsB?w?}KFH=uH|LwBI|KRLEOpIwJ~GnlDj=i=yCu?~Bz{NzFFBxOUyBH~Mz?x=vBv@xAm?j;oAo=^=j:Xz6]{)f1j5vIqDl>oBk?m:xBi8n=i?n?tFr;kCs?m;i?lh:iB~Dq>m@l@o:p8mIB?|BvIn4x=m6`bCp;w>r>l?i3m7kFmDmBx1o;kB_}3j0g=g~a{1b7\4ekEp7d~7h{6m>sBoImE{H|J̊]Qo1Iq>ePWBEk2=k,Kp8Os3Ch(h+Ea6].X;ZBh'Af(If!Bg!@e"Ed$Jj"Hp+T{5?k/Iq.Im%Oq+Kq#Ny,Rz.Oq'Nr4Ir/Or(Lp$Rv/Lm#Hr,Pv*MjNw(V{3Ox2^FS6To&P|2Mr1U}-Ln!Os(Sx)Lu)Gh(Gq+Jq2He)Vq,W|jCl?j1r>l@jAf9b=`Fo@mGoFcAjGm?mFq@hPr@zInHpGrB~B|DL\@sHP~L}S{JwIuG}CxNyGrFJ|ILuGxItFsPyIx9oJsBvGyM}@?t>vE|IvH}I}EMUWTNyF}QyF~CD{@z>MpDk=uBw;rCm;q@rBoBdCwOqGvJzIw?}LCs?n;t?sROyKvEIxDuHNyMLxNtRvD}WuEK~I~O{JzPy>yAwEIGuB~H}LQtCyMvB~@zKxHyG}GzFuC{@pLuDrDo@lyO|AyKqBlEqArEs>q2qBs6gAd3kCj4r9{;xDu:d9l}EyGsNyHvBqBqBvHwI|G?~JGyDuCo9yGuD~A{F}U}A~F}M{=r5tLn>nBnBps;s>tEvAwB{AvCt=l:i.u?nBm=mHl9q3v?p@r=i~/r@yB{?xCj8i/k3v>uDr>g~7n@v/i9j7q1z=oBn>j}0c~;k0i:e9n;vY|7]|5Ur/^u1h6i>g|2kh'Fh$>b#Gh"Fe%Cd(:_6d5]:c(5[&8d'0[*.`*Eg-Gk&7b!7^:`&Bd'A]C]#Cg,5a!9^ >\,S6]7d$Hg @i)Bk/Hi#Ei$@i$;`!4b';a!Db@c">f#Bi$?a$IeNk#Pq'Jk"@h"Ii'T}3Go"Hq'Sv$Lw4Im!Nx1N}2R/Js9Jy/Go&Oo#P8Ej'Lr!Mu/Hp-R|-[})Ls$`%d$W5]2U1U|2c|(Rp$Wx3T3W3Oz)Jw(Ms)Mw%Ip#Tx&Rn"Ox$HkOq'Mv,Ty(Qx(Kw,Fm&Ft)Gs"Jn$Pt'EcFk?oGp%GgCk&Ai&:o)DiFi =j$>f&Nu-Fs#Iv/N|6Pt.R5Kx)N}'Rx*Ki$Qq*Hg"Do#Ku"Ix0Im'@e"Gv.Ms(Vy5Su*Vo(Js$Dn$U}*S{2Wz/Ss)Qn)Qx2Hv1Js%Lu(Zw#^v Rl">d"Mr"Km u@h?yFsDtCnF|KyGy?xB{@sG~CMJJ|MxFsEwH|SwEvBz>k;j;x>j>yBr-_/h1e@u?lLmHvO}FxG~5C~PxHE}Mu=yC{Ay<|?|Dz@wF~C~EwFl6{kE`}4Zy0by/[@d}3h}1_n=v=g4d}5h@hz2q6q?d6i{+q-q=s?fz2i}:i{/g=kCi?c1Yv&v/\w,Py/Sv+Pu%h?j?c0e6[x+b|+Qs*\w5_B]|7oBe:qA`|4b{+Ux-]3i6oHk@v3|>l5k0ls9As=pBtKtCp3`9`1k}5_u7d8]~-dFl7i9g.r>w8xApIvElLg}f.:l3Ak3:_'5o3?n&;e!Co/Ak%4]!;d-@o,Bh':^?m.8a$6g'?f'Gm4Bm-Bl)f"8`$An+Hn,Em)In(Oo%@cIe!Dj#?e,Cl(Fm#Bo#Hp/T;Cw2Bp0Ml+HfBo4Ew/Cq.@v0@r+Bl-In"Ii@o*[B[BCv%Ax+Cs+HlMs'T|6L{0R{-Nz*Lz+Z(].\(Rz-Kw-P}1Jw+Ry/T4Pz+\z$Qt%Yv*Px&Tu0Ps+Nz)Jy'Nw#Pv'Rx+P}1N}2P~&My%Fk!>j$Bg Lo'Fj+Hu0Hl'Dn,Lu.Hr'Y}'Gn#Ow*Z}3Kj#Cj Ns&Ft$Mw*Nv-?r+Jx/Gr&Kx.Wz,Lr'Jp$Rz.\8]~0[6b@\@]?_W},L|+b<\};h:?Y@i9j!Fh!Jt,Lq$Lt$Pq"Tr$Km%Ed)An0In$T{8Qx3[6X/c>e=WB_@e:d>eBg6j?mHjGtHf?mCf@e;ivGoPsWvHqKnLrF~GGzCteJtTsCzKvRtI}DHuJVWR\IvIM~QU_{KQaLS{GyCvHvPvRxQxKxIsDo?tEqIjM`LjAnPnMJ|L{SMR~Q}Yl|Z}FsCuUsMPOrGqEzGjCjCfBt;y=l9i;g4e5a@vwP~BvCv9{Ap=wGwB|:l?sCs2u?v=uBp=g>jlBcgA]y@aCeEeMeEdB`Ca6_=]4f8]~:_@a4g|3_x2gz6Kr0T~4Qv6U|^|A_v5zjBEo5Wx8Ge-Or.Hb"Il.Dm4Gf*Ch(Gk)Cf,Ah+Hr/Hn2Kh1Jr(Mr1Jl0Rs.So.Mi*Pr2Ik.Nn.Mk%Fg"Np&Mq#Ii$F]$Fi)Ei%Nl,In(El(Hk(Ws1Nn*Lf#Jd'Tr3Ii&Ef"Gj%Fn'Fb Bd%Ef-Il2Aa$?^&B^!@\!;^Rh%Oo-Ge%?e,Hh*B]Kf%Eg!Gg(Pk$L\,Mm"8h-Jg)Hm+Ae#Gl'Km+EaAh+Rr7Gh)If'Dm)Qr,Ip*Lj-Ln0Lh)Ui+Mk+Ib+Ml*Ku%Dl#Li'Ff%@e&B^?h&Aj%HgCeBgJf$Uu(Go*>h&?e(Lz)O~0Lz Ml#by.[<]w6Qy4Q}2R|(Ks(Kz4b7c4`@V}8V-W;X.b7]A`8d=^:[>_7\1`})gCb3]|(W/i|3Zz,Mt(Ry,`|2Z}5_y,Qj&Ro"@i"[;Q|;[D_0X@`}4Vu.Sx1Qs1Iq%Ov-P~4[;eClNtAkA_:b0d;`4]g@_3d>nBfAjDiDpCvAp9uH~DzLwJmF{F|V|GxIoLmGqBuK|CJyJwJwJuGxLt}>rKhEn=z?r=};u0wBl>}JsFq9u8h9;j?j>r9r2lBt;o?tKqCt=nBoC|G|HyH}B{Du>zAvCsBvFAyD|DxIIPBPI={MOApAwHw?y?uBzBOGR}Hq?qJqJ{LxJ|Au@}@x?n?tBqD~GwL}VxTG~G|Bw@~=mAh;gA|H;z;y3@ByAv:xD=HwHj=d|,q~:k=v@s?x2s)l9l:s9l@q;k?y0t3s8irCpo0h4p:c}1mC`@_z-fy'h8\v!lz0Qp+`y1^r'cz7Xu0Up-Pi#Pi"Wk'Qn,Pn1Qo1Qi!Le,Xp#Ux(Ro)Yp,]x+Yr/Ti/Xv3Pl*Pf'j*Al.Ad'@b1Ag+7c/Ct@Gn-Al0Co1Lr)Em$Am.Dt:Mr,Lp5Ir/Mu-Oo&Lq+Fp3Dm3Bm*Iv3Ho1Gs1Kx3?i(Er-Dr0X1cBd7[z-T4[X9R:Z1Sc"Dg$Lu4Nk)Ok'To'Mt'Z|'Lt(Yz1V|/d?Q{0QfCqDuExPuMATR}H|QxR{VZU\~\|T|\~M}IyIIGHCZyY|PuP}KH~HqF|GxCgSqAtFu9y:LAu?}CuCpDm@uCJyHyThHeIlBh@fBqHjHt_}F|BvFyNuCOPyH|LzByMkEv?o8uCnGyMq:vD~MvNKrKyR~GrAzM{@uGdHl>rHLzJ{FiJnDxBxM|SrCwMk7skFn;gGlFh;r2vKp>oDoDn9b:i6ncDkAk|B~?x@zKmGr8g4g=e@mJdB`8a5_z:]j9b5lxEqKyTnGpDf?i@iDoEsLlGo=pGt@_Aav6c}:j|>uCne;oFn=mNkLjJoBf>s?j8`}>gAb~-S7S~?Y}0e~3l`}/j~5b;\?Q~9b9b?q6_8c2k:W}6c?Vs0c}2`v1Tx0Ww,P{.Uy9eAb7dAX?^@[?X}5a=Uv8h{8b}7Xw9Yv8]5`y:Ps6\x=x\GBi9Ei0Ij9Sp5Cl6Ce28f,Di)?e&Dm4Mi-Hl2Ei(Ml.@e0Cn+Em.Em1Ej)Ri'>e*Lt4Ip7Bp7Hj%B^#If-Ig*Hp58Z(;`(@j,Hi-Bh)Bh+Jf'Em)Ej-De"Ln.Go-Ir4Fo+Dq5Jn0Io1Ih5En;Bo/Cd0@i0>^!De$=W"Hc$Dg2Gf"@f%Jo*@o+Ej#CcMt*Ol(Bi%>e%?h$Dl'8c$?a<_%C_&?f/Ag,>g2Ff(Fc$@_!Gb 3UCg,Ca%Ji)Bb%Ji*Gk/Bc#Ja#Hl/Ow2Ou1Nq.S|7Np:Io/Dp,Qx3Rt,U{/M|BCf Nq0Mx1Cl(@u2Rz1Ry,Y|+Lv6Jr+Qu1VBZ8U-V|2V}/Wy0Z~2`=Xz4X}4\8d>[z/k}1b1g3Ov/Mv4U;Q8]0U~3Xx,Xw/X{+Ps.Lt,Rx0`.Y}5j6R1Z1Xt(Ru7`}0[~1e~'`6[{*]3X=`GaEa@^z.[~4_{+V~1Zy5X{.[}.Y|9R{;`7k?g/Z2c5d7Y:_=e|,Y~*Pu'Vy/a~-X~;eA]F\5[+o:q1c<_=j:^|+e?g>`1i4tBuAd8e5b.[0W7Ow"P|/[6c7[}(_y(a7e4`>h<`z-i9g;b~/j>];\9by.eCb4Z5`:f5l?j:aEi0Zy._.\;`5Ux'X|,Zz)Z;^:e?W4`2Y}+[x/Y~5Pu.Ty1Wx+Ry/U|)\w'Vt)Qw)U|9Su0Rt+Ks)Q{0Nw8Vu/Pt,Ms1Wu*Wy0Ou/Mn)Mk&Ck&Gc%Fe"Ki)Sq2Tw,R{3T;Mx'^v6]v?]|;\{8^AV|u?mLx>e?d@uKmBuCq?xCHyPuMyOyBPLLGHwLv;mDuFyF}CyDs@m>g>vEuFfIiCsBqp9f}?dhBw?t=o=q1l?e?c~7]~m@o9n;iAs7z2wCzAu=u2j=q4i4f/t.~@xFyB|Lk@tx:~Bs:j;s=m;fEhC`}>d:b|2m=boJd@uM_Bf?q6k>wFkOrEyCqEj:p:jFo~?iDd}>^Eb?v?q9}:xLmIf~7uCgE`Cm>f5~Ei7mBkBuE{NpDrDe?s;h=k@tKn@pW{2k5iCnGgAk?`~@j?n?iBmDl:_Bx_y9b>dv1i{/m5r2oKlC[v;[y5d;nCnDiGfAn?cCc|Afz3cx>|d9Bn3Bi-Ou(Ip-El&:Z!Bo-5e'6d(:e0>q5=d*?s:Js3Dp5Gm&Bh*Hk&:g)Sr.j+Cl+Hk.Kq/Ku+Er+GmBj*Gp$Ai)Ks-Nu5Hv7W~+Y~0Kj"Fr2Ht,Om%Ip+Or3Bn+Bo)Hl'Dl'Il+Lj+Gn'@l'=d$Gs"P;GeSx*AaDh>bAi$Di(Iq%Ks(Dm&Fm,Hl'Co(=j*@m+Fh#MlKp$=i)Nu+Ej Lu-Hv/Hp6Hz0Gr*M6Lq1Xy.e0O|3V}3P{6[|.Rx%Q(S)Mx/Qx0Mt:Iw3L|4Jq$Hy'Qy&Nw)Nz/_:Hz4QAS}0R~*V0U-R;X~3`5d@\3a;]0Oy%X~*Ox*^g1n>nBs3f5iEm6d=u1s2ir@k7hBj1g=f(a2b1h?v;[w@d1]+o4l2j#h/d~/d.e:j:s;W,g(b0g/x=n?f2\-V*[7_,j8a-_6b7Tz/\1`1X-X)Z},W{*_}+Mt(Z4V}3U{,M|.Pn&Z!Sv&Zx6St%Lx(Sw'd|#c1e}(Ww)Vm ^z/S~2Ly3Qi$_s(dBb:q?b6k6|?rCqNzPsHzK}HyJ{OqByBy?uH~RL~TR~ZV}PoEu>yGq=xZ}bzO}MGy;xSvPp@vFm?vByCvB|H}Cp=:v:qAuExC|:vNrCvLyXuGyFNtC~DXwGr?}CXURuGzAL[yINNQ|JxE|>TCGSV~VK}E?|BDsA<{CNMNDvG{=xtC~?@{o:n8g+e6o5j6j}0hCd7cBe0r~-l+f2i0_y)jAZx4b?i=j,r*u3s3r;j=h>h?i.y.o:h/i3_~0d.l2a9cAi9i:m8h/`2g;l9f3d/w6g(l2q2l(k+a6^/S{6U|,[y)x,u6`Cj>zCg/h.t'q6m1Xu.Pu4Wq,]v+^~1]5r2c~+a.e:^y,a}6_3\,b~.j=x@w7oBp?sJmBvAp9i4n:g};_/e7a|6_}4a}*g~(h5n0d?`~8hBjDjBe7j3j;m-lz4e}Ak-i}-h~3pHhBf=d{.jz'h2p@q=f:f6d;ja1n2fBj6e4a+s5a|*`1[}6a~*Yy0`>u>h~6]|6bv0Yr0Yu,f1Ry6\u3|fDLr7Gl1Cd,Ki-Pp+Ck,Gg*Rj*Bg1Gj-Gr1Dm.Bl1Ii/Gf,El+9i*Cm*Cf.Pn-Ej2@f(Fg'Ae+Aa(Ii+Dk*9d*Aj,Cj/Mq/Df)Ce(Nv2Ov=Jy8L|=L~9U}?\.Vx%Qu.Uv,Mw1Ty9Lv4Oz8\}+T4Ou+Py6Tr+Qp*Oz2Sy.Jz4\2U}3a}2\~8a7S}@OyeA_7_9g5o:dC^5`4g9h=Q{#c2Ow+Vx5Ky6Ru+Zy,[~8U:fDn/Z~9_;\|:U=c>a9`Bm=e@f-\*c?_:k8mD`/k@oDk8dBk>t5kBk@n=q4\z-]{3[r(Op(_u-Zw+B^!bg"Uv&ks7qEkC{JHyADAKPqI~MLxCtAwI~?tlAc;h=h5gCrJea4Yw,aw+b}1ov'c~1a}.\|/^2`3c7p4d/`},]0do;l:nmCi>\|4j7gEn0i9iDqJqFg>p3e~eBro>q5u?jJe~Bh~=o8r@h;j6uMh}0GFrBlFyp@zMvL~Q|NkJkGjAwEu?rEo@m|DfGy?hBjFq?xHp=a}=\}6hx0g|?l?gt6b}6iy4i~9by?i~B_|Ar5iB~8l~6o6m>oCgFlH`BoDo~5jBjMjFi>m@bGc@g~4f>n}3iz=jBcClDl@xdBBn1Jw;Ir5Gi$=f&Gh(Ir.Cn.Hr1Gl%9e%Ik+Pp/Fg.Ii$Gn)8g$@i*5`#:[=f"Cj$Gl'Ai%Cg&8`):m*;f(=c>g Io)@l$Dg"8c&@c#Bi):f$@fGf@l#Fk"Dd%Fg"B_0f-Ou.Fu-Lp+Hd=c)Ig#Ee#;f%Gi'Gl&Io#Lm.Hl#>b%Gi"Po#Lp"P}/T|2Dr.S|=_~5Pw'Am,Gt9Lu,Kz0I~DKu3Hr-Jp,Di&;g#Ci,Gn,Uz6Gr8Bn6Pu0W6Pz:O~6Jr3Ty1T;Q-b|6\:Y{+Ty*N1O}4K~T;Q<^;Py7Ix5Q2R6Lk&Fo-Lu/Qs/R}1My2X~:N{1]z-Ru+Z{3Qw'Lx,b8]4Y1Q,`6`8f1aC]oC]:b*Z2nyL~@tCGx:w@i@qz?g;u=l3vFr>}GyQ}MqLqDfBl|CyI~F{Lw>yJs;mBs-[OHsEx3o,h4f>j1pjk=d;aCb6d:Vy-Z3Yy2cx3^}7k@b6d7f1v1v@s7p3f-f:s7kFj}6oCf8z;kLr7qq2lGxFjy2fCn>|>lMr?jHoCgKu

p:oGi;i=l9sFu=nBcCe/p?p2p:mFpFuLxBEqGs?7@}O~L}[rSvEwDFsIr?x@wG^Bu6~Ou@r=uCs;k;z?nLkHj:jp>e:WJHl:Ox>CkCJm6Jx=Or,Lm/Ln,Rs,Ot.Fd*Ku9Ky8Vv5Vx1Iu.Jc&Ls*Pv,Cp6:n,Or4Em1Cj,Ll*Kn,Jp5@n-Cu5Bp7Bi5Em-g*@g'Fo0Lu.Mr3Fn5Nu/Ls1Z{2Jn'I{3Q{1Ow.Qv-Gw/Sy/O|5L~;Hl%Rt5M}?^/H}9=i-Bl/Gr:S;R{1Lu2M~/Er5R4X~/R{4O~6Rx-M},Gt-UTD\L[HZFN|2Mx._HZ~/R;P~;Y/SD_>Xx6M|?Is,Vx>X{6Fs5U|._?[3^2S}@Qx6Ox0Uw7Rz.R{;U{:Uy4Qu4R}8S|;Ku8Pw0N:\:c@^1Ox-S}7Wy1O}6M{0\7Kz*c?b:R3c6`?gNb7gA_;X1i;_;[<`EeHm:jE_;a(b2mCd1^7g?_5`0a;`7b2]8R>P|;d:W0Y6d9_.`7T~<[:dB]4[:]Be3X9d5]~/V};\F]A_-[1P@Qz2Pv0[1V~:XCN3W>YE]6Z|0Sy,\{2W|8fA_@f0\<[9d4bD^7RD_=^=^B[:T{)[8]5_:Ys@vCoMiCjIfLeFnKoKuGpIvFpLsHs8iAqCs8ki8h@m@iDj>j7q7h8`9b~5W}6i>_9`z+c1kDfBl2l>]|;aCMv5`~,f3b{1d},_~,f2b>Z:r=p;f<`z4j:b}7hx:ap*`u8]y7Rx.dz/\1]t,^y+Qp/Y|?_w9_|:Uq(^1_4]x0c~3ay8lCX~:dDm?rnHjNtBu@nEi:j>oEfBsHkAf};c?^|Ad>u7|DuFxFpMnDsK}LuNqQjEDi?w>sLvR~DlE`@o:gHs@pPpOiPeHa?sBg7`z9d2cBeBoJfF^Ab=i:g@j{;[~CdCgHbCgC|eHZ4My:W{5It3Sv3Rm*T{4Py.Sx#N{6Wl%Uv5Sp)Rx0\5O{4Ov8Ss%Mt.Ss'LiPr$Md Jn$Kq'Cj(So(Pt2KjNk$Eg/Fk(?i1Ai-Ci$=b"Ch DdEd#Bi$Pn*Jq+Iu*Hn-Qo%Iq1BcIdFh"Ip&Bm#Kr#Qv-V|(So)NjPr$@l+Kl'Kl Bq$JjCj#Jj'?j&Nk$Ck'CdGc=b Mr&P|-Fl*Bn1Fj(In/Gn,Lp%Fi!Rs(Mx-Ij&Lp'Lk$Kp'_}/Or$Py*OoRk$Zz)Or%Ih"Qu2]@U~2Uz4R=Oq(Mm-Lo*Kv.Lu.MiL{1Q;Rx4Q|.Lu0Rs+\}+Sw)Sy(Y|)^'Pr Xw0Z},Zy$X{*My5W}3S1Ly5Tv&_9V/Ry0S},^az5W~.Y}7Nz)[},Wt'S;eC];^5gCd6d6]~0X|6]|,Vv+`?Y=T:[-Wz(S}2_y0]}+\}-V{&Z~1\3]}"_2b6a3Ry%V{$`'d6h1j9b~1cCa/_(b9c-_f8h9i.m;e=_7e=b@j`z+Yu.e~4Nx3Xv*Xu-['f-a3^9Mx;U},Uv-V|4Hm&Sx,[x$Z}.Tu'Ls%Sz6]}9c-d}%Uz'a)\x+d}&\{/_{*d}3]o,hw(Zw'az*]}'Sy0Xs)]x,\y-Tz*Xz"NcEXK^Ui]s!Ys'Wy1]v)_y,cx*_|.`~4r?h?o>l/qFq9{=p;x;~:}PsLyNkApC~FKIX}HI@ENG|@zFpCv?rDyMzC{JtCuCsN|DyIxMrGw@y<]x:u1pCA]tRr?n;l4b~9pB}?G}KwRVXW}Vr<{HG|GLxF@tEu:u8e*u9j@q=nLvGu@p1iz*e)n=uLpDyCmG=~FwA{5l?pGo7r9qEsId;n6v0f7^;g~1\y.ez+Wv(h/o1i=lCf4l;l+l9^}*o;e1h:m=p5s)d6c!m+i?n3m;c6i4s7k5j,i,hBl?o9p/gu*hz%l*q/l2c|4Zx,j{&a5n.}0x2j9o>a=j6k7d8r?o8~HtEp4pDqF~CB=;~0r>s3q4v:j/s0|9p5t6n,w3h4pB4y3p}+p~7qE=~AxMKIDLzFJ:vFt?KEVPPAIv9qE{@yQ|C}JGs9y@y4m?v?vGvHxBjGk=r=h@jEp@k;nIqGkBt@sE|]USy:Ju9Gr6Jo.Jo0Jj4Jx=Kl,Js8Io+Hr5Gu:Fp5Hm1Qs9R{;Hq5Hy6Po*Hr1>p4Cp*Nr0Ps7Jq.Pr/Nt.U6Ct3Oy3Bn,Jo,Gj-Lr/Eh'g*>g$?j'Fl&En)Jn&En-Rs/M~=Fq/Py/Jx5Ju,Pw1Kw-Nx6P|3Fy1R}3Ny.Oo+Qy+P|,W}.Gl0Nl/Lp)Nu*Sr&Dy2Sv1Lp2Lv.V|5Pu0Lz8Ou(^z1O4Ly1Nz9Z>Ir-Jt-Nv4R5P3X?XATy7X~1S:K}1X6S|0W~0Z~.`Db>Y~.Mw$M}0Ny&Gu&K~4K|=Os1O;U~/M{5X?[5f(X6X@[}AX6^~+\;\.W>JGi>^H_ET@c@b;Q8_E]?[9X?ZC^=]?a4S}4Xz-R|;\8_;OGX:]1a/Z5iCX:a5[:Lx,[6`4X6X~5X4P>W~2_:X5[:`;h0gB\CbAc=bBg2^1Z~-[7`Ff0]7P;_7a8e-_4\8b6eAf=gKa,`;hGa2h/bB]9b;^L`B\>_6d9];^<]?V@q;`4_Ac6b;Z:U/[3T>Y}/^4`8Lr/Vy5Mr0Qw6Hx4O{:Nl)Ps*Pz0Mn%Ih$Hi,Gq(Ho,Jv0Hv0Uo%Gs0Er3Ig$Iq,Mu&My,It5Op*Dj(Gg%Kt4Mi!Mr']~:S~6Ht0Lu.Pv.Sx5[3^4Y1Rz5Lt-Kt3Dm*Vr"Jp(Ft%Hu/\|+Qt.Ly0Hr.X:T}1`{(Pv*Z6\:`6Z<_~=W}?_s@e=sJjDj9v@xD|JiDnCoKhBgB}D|HwI|CqDqHfDdAqDpO{P{DzLv@oAeBb3lBtEcAl@p5jg;mEl?mj;r@q:p9r>xCuDf;j0q=m>n>o?nj~@nBv=n?rC~AwEvBt@r7}J~Sv2|GtMxHlCp>nAh>k{?r9t?sw5q3m5i@s5qFyDo:q;p6jDh@q7hCNpKx9|GsErCr7iJm>hCsBqFkFfB_|:_x@ar0gAfCdv@uBX~IGi=Ks@Dk;D_5=e>;b4Dd7Fi7Qs:Mn1Bk;Ed.:d5=c(:a0Hi+Mk-Op@Iq:Di9Ro1Jg.Mo3Lh,Op3Nq4Ku@Mo0Lo3Mr4Io;Hk6Im0Mm-Om)Lj-Tx8Nn0Or6Pm,Iq-Fr3Mr5Hr@Ll3Lo/Ol/Ij2Hj+Cg.?d#?]#@b+Hg,Il+Ij,Nk%Kj,Nm+V}1To(Ri'Pu5Mq)Lg,VCIv8Sz+Rp'Kp0Jl-Ie&H["A`"Bj3Jh.Kl+El&Qi%Lh2Lp/Mn+Jp-Lo4Pn/Qw0Rv1Lq4Fp9Jp,Ms3Vx;Py;Pq-Pw4S~3Nr1f~2V|7Oo4Cj*`|3?k*Do(Pw-Ss,TxW{0T~NdC[{5fGe?^;_=^=h2`@[}4_;V{7\3]2[G]~2Lp+\u-Zz2^2X{?[y2Mv5[7WZ|6Qo3SB\HPw/\{0Xw0c3YFp'Pv5Uy=Zy7_}0Wy2Nw0Kv0Ux,Qw/O|7Su.Pw5Ln'Ry9S|@Kt7Lv,Wv0Ps-Cn0Ri+Cm6Ai2Ei/Sl'Lr:Ii-Qy5Ii-Us9VxBGm+Lv5M|3X:Tw/]}AUr/[|:Yz:Qo1Z|=Rh*Nu4Mt8Px?Ww8^w/Sw-Us+Xw*Ox4Hm,Fk.Ss$Kr.Nn.Wx*WaBmJaC]7g?`2c:f}9\7V|:bBb;]:i8a~/`}(Os0Uu/]{2]9a8X|8cz,Yu)Vu*Mr)Ts(]q#Wy3Me&Sk(Su,]w&Qp&OfNg)[u3Jf0EZ$J_#Rf%^q$f9`y/Va"\w*k7iEgCn?oAb>j>lK{]wN}SRQzW?HzI}RN~NuZ~SHM|>m@p?|FwC|CSxFOJyDEM~SrAxC}GLB}SR~GTKJELyMmHzOwNyFgRlA|JzLyItLr@d@rEs2jCp9s4d9m|3hCki;a;z@sKl:f}8f|8g?h>q8mAgAj;s:rCtDp;p?mn;ez3of;r;nfx:fp*j{2b;lBo8oAr@uH=xKpGtEuNqEoLdCog}@tGn@x:iv;kA|REJ{?Gq1Fi.Np0;k2Og0Cp4>m3k1Bm3Dj0Ae)Eg&De'Bj+Gs/Hr.Ho+Es/Iq2Cw2Mx?Ou0Br9=m-Jx5Ot3Jt/Cr/R{:Is7Ow4Mz7Hu.Jr.M{7Fq4Y;[|.X~6Or.Q}/Fy:Z~/U.Kp*N}.S}.Y=R;R}0Mt*Ht1N{4Mv+Jq(Tt7Pt,U{*Jq2S}2Uz.Qy0Ux0PDW4Ju0Nu)Lz/J|4Mt/Lz4P}:Dn3Lx6Ku+Ch"Lx/GbLp(Dm-Nu Lq"Gh!Hn'Gp.Il0@s(Lw4Ov'Ro-Hp+P|,K|2Ex8Dn1Lz;R9Iv/Lx6My1W}8Z:N6S9X0a9Rr+^0b9]4\0O}.^2_1S2Z}0_}-_5\~?P{-_>Z3W~8XGeDf3`>_?b5e;\l%Qx8Fs*Tr*Ej/Hs(Gq)Ly+V3P}.Qy0Z=UBW~3Rx1]~9f/[9Pu,Pp+Nn)Qw-X=Wy,O3S3[/Pu&Gn*Jr1Hk'Sw0Vs+X{-@m(Kr$Cj'Nr+Lx1Cr%Ou,Gr(Ip)T}2Wt(Zx1Sq%@u5Iu2V{=L{BT.Ps%My8Ow0Tx/Jv'V2Rx-Ks'Tz2T{;Ly0Iu4Sx1W}0X9X5^>f7]3f~7eA_;];Y}.[z2m0h3a._8_)[z;Zz&Ts#Sz+Z{%_~%]}(Rx-Vz.]z,Xy%W|4_t)\u(Mu*Lx1`}*VBSx;Z6by3a2c/\|-^{-`}2Hc!Vs']t$Gi#Rv*Oo!`r _q,Tg"Yn#D[G]Td`z+\|(d{'N`Z}.j~.mLwP}RyHy@[WKO~FfR[zH}B}AhEpFqCr;sF{UzI~MnBoGdFqDwOuBm>yGoAkBzJ~FvGyL|SzIz@vHvKA@EyFuHH~?oGeBp?jEz@xKi;g:q4t5k@nj;g:e:d,_z)i;f0X;ZBl;m~4jAq8n|5a6]{0c7gAq?m?k/i3e2_{1by0b~5l:^|3a.j;i=gCj3d6n>uBn?p3p7j3j=o7v?u9pAmBl5mCh7u9sC]|3l4f8o2q@p;os@u?m5oFsEzItJyEtAq7t?JyEJmEo7hn>sAjDmE|CoOm:p:i=eBgDPt?@i3>g13d,7d2Ir2Gb)=k:Bl39e(4g6n3Dj/9g*Fq/?q1j+Dk,Qw1Lq,Lu4Nt2Hl-Pw4Kv7I~=Fo6Dr8@k,?j+Sy3H}?Oz9Rz5Px+Rr(Oz1Jt.Jp,Mq5Er1Q|/Fq&Dt+Es'Lw/Oy7Hs.Mx*Ir+My(Kv(O}5Ex)?j+X}0ms+hi&\:Hr3V)Qz0X}=Xv,Qv0M{2R{BW;XBf:Z7dCm@W?hFb8d@\5f7c>d6Z1Nz,Y~,P|1U4X/S~0Gv0Hp&Uv.Mv0Ju)Kz1Px/Xd;\=Y>V0X7a:Uy-V3\=S?]@]2V7R|O},Q{/W;^5e,c:U:Ky@U~9Sx1Q{3Ou/Hr(Lu(Oq,Co/X+b6U|0T}1T~;a5W5Nv1R}3P>V|5Xy2R2Ny+X{,Tx6T~9O9X>Z6V6Su%[}2Sv.Qt,Gu0Mt,Nm*X}5Gy+Y};N}>Dn,Wu-Nx-Ms,Hv3Dt)Cl.Lq(N~5W|.Cf'Hr1Lu-@r.Dk"Mx,Gs)R|2Lp/V{4R|2QS};Wx+Pu6Jt.Rx*_Qq#TXsg$9dw3Yy/Kx3W}:\w'Y?Vy,[{.[v-[u'W|?YWv/Ko-Hz:_~vFsHs:ni>r?yFuQuMqBee}*h>epFoEh=g;`y6s6p7ez,]v2c|8]4Wu2_}:b{3\{0[}*\p(`;k7h>r^Ie:fCf6m>pHgDb@_Cd8l>t@eGk=]BnDqBxNxHrMsFh>i>gAh7Wz7c=Ro2bz:Mq4Ae*Ci(A^)Cf17V-Af/Ag4@d&Cc%Kb);_#<^/:e,/`&3d/9h53[#'X&6X%@e.Da->]'*^05_,+Y#/V 8Z&<^"@f/Fi&=e5:f*Ae0Em,Gn,Fl+Fc)>X%3](@_$5a-6a+@j*;e'Jk/Dh+8c(Ou,?j+?l,8b*;f#7_"@f+Dl4Gh4Gl/Gl,Ej'Pp(Mj,Hm-Py:Eq.Ru+@o8Ah/Dj0Ec"Gi%Kr4Fm%Je$Ie,Eh+=h.Fk-Ho-Fo6Ps.Fm(Kn3Hn1Dk2Go9Mp/Ci,Cl=7i/>g0Kn5Lo.Hl1Ek.Gr+@m.e:_5e?\5gB^>`9a7Tw)Z5Rz._4\c0O{0Vx.Yw+X{.Rx3Lu&Ls-[u0Vo-^v*X~.Xy+Wu.Qs,Wy3^3Lu0Y~5[|3dD[u!Ww+Qv/Y|>Tv=P=X9Z~5Ny;_>]1\{/f.e7^2Yz5[}5R{6Nz/Q|2Wv)TA\GWAZA]:_3[~6\3Z3b5`4P?Zv/Rm(Wx1Mv0Pu/Bm,QyUw5Og%Wp$Nq*Pv%Bl.Ju.Ix+P~0@j&Nm'Vq.Lj)Ou-Pw;Q|.Vz.T{0Ul!Rv)Bs1Gl$Ij#Mo&Ht,Kr-Ok&\u,Lh(Da%Df$Be$Im,Hk$Mx-Pu)Zv0k~)n6tk0lAl6m1g.h8qBb|.`~,]x*_z+q3l}5f7yPtb;f3c;e+`>b*e=dIhBp:^m?uAeGsBm=t?iI~CpIi?v;iGc@d~3kDmBi@qF_x/lCnCgREu>3i=2b8Gn+@d,@q?Jv9?u8Kz9P4Js3Ky>Tv3Gy8KD>o,Cw4M{/R~3Ox3>l4Jx?NzFJn.SAL@k2Gn.Io6Bl.Fv8Ag+Gw0Ky5Rw/Nq2T9\}7]8N@N{4S?R~4\}-\?S>S}3Q{7FybIJy0Iw:W?]EW=Y?X3]@Zz.Rw1Z~2P})Ru%M|1Z0Zz)]5RSw0Ox,]z0P};S{:XBX}(Mr/Iv-Mw1Z~.T{:Mu/Rs$b{0W3\5P}9V>Z>Us;Pu2\F^GU>Xy8Iw7U9S{?X>Q{:Qy5Tv1Kv'P|6Mx4Nv7Xw/Qw3M{:Kw/Gx0L~3S|/Mx/Gq.Fs/K{8Cq)Ht2Dl-Mq,Pz4Os/Sm+Qz1Mz4Ru3Mv.Dj+Xx.M|/Fr/Sv,Lm(Hs.Gr8Hx3Ju,Nw,Lt&Kq.Ks4Ds0S~4>i1Js2Jt+Nr,Dn+Ms&Ov/Lu4Ps1Mv3Ny:Ls0Ak,Gv:R|?Mz9W?Mr1Ul>d>h2d8i6o@vDcClHs@h;l3g7jc?j5f9d;j:l@dCa:j6nCn=g@fd1kNnQoDGtBoQyFxQse@d>bCe:Vq-Us7dx/c{,e1i@p@mB`;i7lA]~2g9c9j;hDcY|5Wy7\v3}Gn94c-5e5Ae:8`9Ei2Mg,,Z&*X#@d(Ie,Fb*;d3<]/5]88`*Aa.:g,6c.@e0;[*<`4=e2Dg3=g6@h/Fu:Em2>_'@c,Ad'6],-a-Gr9Aj48]#Ch.Cf'Eb(Ee0@c%Cg+Bn0;b/:p1Aj/Ao6Gq5Fm*Em/?g0@j9;m8Bj':^/C_Gb!2_"4e.8f.Bg%/^,?pA?d-8^*6\)1\'9],3\*,[(5_-@`$3b44['<_0Eh19_+Mv@Lv9Fl)Nz7Es7P~@ZXz8Z@X:PGR@O}7S;V{*U~4W?\4^BR?UF^=XA^>^:^:Q};Hx2Xx:Zx4Q}=Xy?]y5\3R;Z~=Q}ZD[}6X;L{:X~;K{=Ms1Mt8Mo.Ry1Fk*Cm.Jq&Ku*Ko*Qz8O|:Ur1Sy6Ae'Cp%Iu*I}5My5Kp/A]%Mg3Gn/Mo6Di&N};Ry)Mk!\j+Xy:Lq0Ny:Dk%Hq/Hu9Uv2Oq2Di,Eh*Ds2Hwa1Rz/P~1X}2]1YySu3Uy2\COzYv2Or+Hl"Jo%Jq*Gh(Lt0Li"Ll(Ku6Ph(He&Tp-Oe%Rm-Wj)Jj/D_'Il.Or*Oz3Py3Bd%A_'@]Ir!?i$6e#Ou-Wx&Os%Ig$Hq.MhWj$Lo*Ae%/WCh(A]!:` Hs:[w2Ux3Q{ZHa@SJb"5N =V2OCd".H>V3I>O!Hd%^y.Mw3Xs Tv$\{-cG^{9b|*_oDe>]{5k5e;d=f}?jAe6U@_~8j};jBj2r0e2_Bo@rHmEbHb~4_}8_w1j?c>gCfy,b}j7i:^w7a}6bw1_|1a.Xu6aq/ct-]}1`~=]|9`=c8gx2dx9e|6`|5eAm:g}9a>f9f~8^q-iCf4l-`u.Zy0Y}<]?iDo@r6rHhBi>Zs;a3\x5Wt3c=`y;[x9c8IpGEg3:i;7j80_)8h==a,;h56[(8f1,Y20W(8d.;c51c59k0*R07U)@c1?i1Ck*8`/Br4Gd%>\3?e+4_,e*7a16e*5Y&5_+Cf+6`+?e(A`67`,7h+:d+7e05Z#?e/1d1DqC1d0>m)Do0>i'l2Lz4S9RGS:`}.R;O|5N}3O6S5X|:O{;N{8WP|:Pw2Ny(Oz0Qx+N;P0V{1S~5S~6Mx3O|4X}=`6Vy6Pv1Wv1Hu;Js2Iv:Cp1U|,Js*Lm/Ds0J{>Ky6Lw7Iy,V:Kx/Fr1LyV5`=pEW|5WAZ;Xy+W~1U|6Rq-\7R|:V}2[B^8Z;Jt2Iu/Lw=Kv7_z3Eh$Cp*Qu+Kn(Kq3Em1Ai3Eu:Hr)Ee"Fn)Js.Rr(Ei&Hv*Gs1Sq-Ox/M}0Jw.Mv1Ie%Po*Di#Xv0Fq%Hx2Xp*Cm+Be)Lm'Mn.BqTv0eHa:]/^*e:`6\~Mt1Xw0X~+[._Oz.]y/Qt'Pq-SeUhD`Mm!Cj,Qi Ni!Qv/Hj#IeA]%C`D`%Ll*C`Oh'F`?a@h!XjWbQe Tl Rl&FaHc!B[EaG[Ld?\G\Cd%2K,K1G=I:L3K0L-DF_BZ7Q9W A`(Fh%Ru1Lp*Mu0Fp"[~0Zz,X<_8o:l5c4i>^/_:gEqz1iDf~9dz/j3]u.Xw,^|4]w2g5_7kiDdAh>k9j~5f6_9h|/b?\6Xx-Vt/_|5bBd5^5j5\~;g>d9mHn{4bv,Y~@g2[}:]|/[:p>oAbz2c4[~>W4a~4bHoDJm3Rk/Ad2;g-Bl98d2Am38d+4`-1d71W.Aa*=^)1Z0=i;4b3>f52_2F`*Id*Gl78`0Ce$Bd)8f*b'A`$?b)6`*7^'Bb,;h-;d->g'Ac/Ik2Cf*Ej,Hp9j+Q{a:O{%Y~8Pv,Ou4Ow-^}3W}5Ls>Nr.Rz3a;]*b@\}6\}AX|0Uw2Qu/Gs6hG^2Xy6T~]y;_~8Y7\;\6g-]Y~A];Z?Z;Z};Ru8Nx6Kx6Tr5El5Di*J\#vj(Mx4Sz5Ml+\{5Xv*Tr(Hs.?m/Ds/Qv4Pm*Tx;_z6_r0\HLz9Rz4L{:Jn.Gf)Jf*Po0Jl(Js3X{U7Vz/_=`?_~4YDX4W9T~:_z7Y4gG`Z:bAfAWy_~SA[M^B]HaDc$Mc#G^$BW#Rj#@VD]!CXHMB^&9LCY>Z%6S;^!>ZMj(Ll)Zn3Ps7\q4`zCTs+`}4]w-]q+_t6]x1Vy5_w9j03f:;k23d4Bm/Ci3=g+9e/7g8:p@8j;Bt6Bo);l'Aq.Ag2Bk77j=Dg'%R)m4._,2^-9h/=n/Do/;i+7f1>f1i*5m<5i0Ej-9g-;i*Gr,@k*:n.4h0Dm.Gr2@x:>m6?l2Bq-@k.Bp&T~@r7@g%?p2Jz7Bn1Au:P>Jq+Mu0Eu2P=Bw2Jv7I{:@p2Kq6Cw6J{4Ds3SOz@Hz:Ky7L9Q};WCXe>]<^DEy:M~>M/R2O?W~0[z;Ut0[5ZAZKZ=[@`>VD`BYA]<]?]AX4[4W5X-^@bX;K}CV0W>X:c>Y>V~7V|3Nw;Ju5Ov,[~0T?U5M~DX}/Lr\|/R;V=K{9Nx?\2]@[LW9_=a~2Gx3X~6U9I}2M?^B[EN?U~.U9X1Px0J{1T/Pz3Lw-M|?Fs0Tz0Pt+Mx-Js+Ir5Ju;Js+Fx3Ns'Gr+Ot0Jx5Hn/Fl)Jp0Ks;Sw$O};Y9L~?J>Nu#Rw9X:X},S5[;[|:[=Y1[?U@[=T~6J}9S7Yy-Or-Ir.Uz4Nw+X{aBf7_9Y;\2i;^7_)=&3 (< = 8&B(@0 ; *8 (C%>5H(E&H!B -K 8V:N,BBR'N'@1L&M,V1H4K5X 0H;["4N1M>V1H5O3H4BCC3O>XF] Lp,Dr'Uw.Um.Rm.Ks@d11V/Fh05b,8^*8c)Do5Ei.Df1@Y%:e6=h)Am1Gq;Dk7Dm9Fi3Ch86d0d*:W(:`'=e3Ae.Cl,:`.Bf9Je'6b69\,7h/An3Dj.Cd+Hs:>j7Ag:Oh4Cj-6h6An28e.=m7>b,?e2Ab%?g-Bd0;h<9k8Em/Ku7Lt:V{8Ip5Jr3Dq3Lp5Ln2Lr9Ly?Gw@Mm6Pr4Jx:Fn8@m4Pr2No-@k.Mm4Cr5Dl(@j)Eu6En/Jq4Mv9Fr4Lu8Go:JvANr9Ft-Hp3Iq;Q{RFU@Lx3X~BN~>Go0Hs-QzRz6Wv6S};\{6Ry5S~6[?V{>U{2[=Tp-Px-Zz4Mz:Z7Y|1PCV~9f8YBV}9Vx0OCW;`ATG`?u]Y~>K|:R}6\M\@sMeES|@Tf7d3M}8Hs7Wx/Z>Jo0X}8V{/S8Q}2]6\|;c>aFXK_@`SB\@e5Q@S?W9S?X@Iv.W>R~@[Da=Y|>NBZ:^>c=h@cC_F`<^A\>`7^<^5XAYJYAN~=S?_>a:[=lAf>iAeC\EYAe@b;iBqArHjCzTcMZEa1gBcBX>[9dB\9X~1\3_BXv0V}?^y8R{@[GdKY|7[~Ff&9]Tk*Ke LaHa(Ws0\x?Qn)Ja#Ml+Jg([w`&A_$FPK`!Pf&Tr2Rp*Kh#Gg&?UBSCW:K>["Hc*De!>[ B_ ;Q;H4Q3K-O8Q2V;Z-I+O1P6Q7M=S -NGSB\0S9JDE5FZ"?TDV =R!D\#F["6O=V9W%G5G;M:S!0L?P yJp7Dp6An;;c,Cb$@i.;e,5a1@m6Bd.7l:=k/Fi/Lp/Sr1Dk.:r35`.:c.Cj*;k.;i'7c)Fi0Fk.=f3;l<7c1En.8g/Cd$Ai*Ll4Bc1Cl4Gl0Bo5Gl-Hr8Bp.;o3In7=i:Ba&Ot3Fn6Ep8Em0Gg)@o1Mu@Bp-Bl1Ru1Ak+Dl2Ap7Bk3Ak)@k-Ak,Hw6Fo3I{CHq4In4Jv>Uz4Jp+Es-Ey2Mw5Et7Gx7Ar@?m9PX4UAS}6[;Z@\=R@\H[?[B\@bDe<^L\|6Q}S}1Y@U2_6Xw*Nv/Z;S}_;S@PX}@Py]?S~3N|1X:\/Iv3Uw(Px+M4V~>Y8V6V~,\=Vz-Lt/Iw,Y:Qx6E}1Y?fA_9OGNx_@]BW|=\u1]@]4`3X{2X8Z|5Jx6My7O}<^BV1]?b=h:Y>]4XDU8U@_9_z;jBY6X;X:T~3X@Z?^<\>YM_=X9R~3Sy;S:OA[9P3Wv-[2[w+Wx%V~?Kv9Is2Lp'Tx)P}1Ty/Kw2Y{8Kp+Lx1Nz4Qu3Jq'Pu1Mw6Lp+Ot1Gp9Dl+Pw/Jr1O{3T~7Hw-Sw/Lx+Pu)Lk'Jo+Lo:Io&Q~=Ot'Tp-Hf#Bs+Pu/Nt*V=Ru(Fl(Mp2Mp,No*Vo*Lj!Bp-Ik'Hj"OgFs(Ku-Z|5Hq&Rx0Px%Rz*\:d.Z>\}8[=X}(S|1_w:[y1_Bc@aBa?_7cB\~:S{2_;Z<_9Y3TBV?`z9W|/_;f:lG[F^=]CW>^7l@r@d?a5_?`=]7X{/Uy,bz2\}*_(_0[{-Rz*]{,\v b'^,c&]}*Pq&]x!Nn+On/\q ^u$c+_-e2[>g~0g8n;\;`}.X~-d9d4_}*d5m7f;d2b5g0k:k5d;b5jd(Ji$Rp.Ea!LaG`AcC]!BYFd?WB[C_A]J`QjTjIp-Bl*C`&Qm5Zu/@YFZJeNe';`#N]F[G`Cd!Ke#@WBXJ`FaHc Ei=XEZBbB]=S!,JCY>V9\=XF`FZHbG_Os.Lc@Y9ZI^Ea Rj'B`=\Bh&@[%5^4R@_Ih&B\7W9R5R=TBVB];W EeHe#Jh'?YJT>\!Cf"A_7YEc#@YBUe15e=3\.7d50c00\4=e2e2=g1Cj1@i-Di8=l2Ae+O}HQB[FMOW}8Rz0P}6M}?I|AVAM}DO~AJzDTBXCMz:Sx@R~_COAP~>Z~Z:My:X/\<];P|4Y|>bDYH[NR~C\}BPt0L}CLs3Pu1CwO;Jx7S~@P8Nz^?P5WDW{;\D_9\;[JaHSFPHOz6[~@\~9W?P|CU@Y|.W~:T~CM?U@T}AX>Hv5R{Ix;U{8Ty4[|+Py+P~9Fp0Er,Ju/Px1Ix1Hm+Sv>Iq/Fr:>i1Er*Lr'Is.Ns3Qs0V=Js3Vw3]>Xw0VBX{>R{9O{0Px/Nr0[t,WCY~:S|7Xx3U{:Pz1S}-Sy;^p(\|0Is;Ot.\{8X{0U;Z|4Wr([u%Z~8P}1R>Gs3Sx:_E^}2X~BW};Zx3cBXJX;\u4Vw*W3Zy4Su.\v-Gt0Lq(Kl-Fm)Nq'Fr0Lf)@c'Jj'Jf%A`(Ae$Ej#Li%Mj+B`%Dg)Di3Gq5M{6Iv4V>O~4Jy3Oz:a4YH^>a?]8a4e-]t+by*[s3gr*Qe"Pt+[u*Wp&[v.b~8Wz-\s+Zr*Ws+c5^}*Xz/c|,hh?a=^IeGX;\6W}5]/_2dw(]v.b@Zy5Q0Wp%h5f+d?xHa?cy=\t*n<`5^}3\n.Kh*Kf%:X#8W"I^"Ol*Q`"Vi&N`Gd D^"Qn)Ca'Gg%Fg!Nk)EeE\C_Ba4Q^#C]3\'I1NGW>W$JaAWIg-@a&B_'BX#@\$>U(7W'BZ:X$;S7W@NAO;N=V A\!O`#F]!GUGX Qb!B_%=_ Gi%Ib!>e"Af3Ab"8U8]$B\ C]"1MAc0R0V?Z!I[$Jo%Lt-Gm5D]":O?M=K9LBTD[Ea";V Ge*L_ F_!>X%=OEWB\%CX'D[-JY$#7 ?1!8892I*%6< C#L'#BC17?@>81A,K$,P&2,2-& & 3  # :9?.N$(D5* , G ,   =+C3J$ D)N&@95.RE <HE$6, >"I(M,N!7S7`,$OO!+R&(U(Ci,Hl02\'/_*1^ /\(W")V&,\$7c,@a&Af)Lo-Bp+@d*4[1;b,,\'Om)?l7Ch.Ki-Lu/?`/?c4Dd+>f-Bm.@f5Ck(Be.Eq6Em-Cn/Ag%Gk/Ik+;h>Bt?KyBJw3Nw7Hp1Q}?WAKz=S}ZRS?L~@Z~CBt@Iz5P}>Rz7Wy6K|BS|5]@Q

Hv+Lt1Gw5Gv:Mu2In/R|>Pu3W|0U{-Fs7Pw1S{9K|9Sz1T{5W~:Ls*`3V>g=Y}*X;W?IxPx3XTy?Jp,V|8Ov?L}RzA`5Tw2Vy3R{/X>Px9Ux0Bk3Ou5Io&X[4a9Ty(_8\3\:[5[?^|2N3Z.W0\?]C\JVz2W3ZA[?X4R},W|+P}4\9Nv;Ux5Vu1R|8Z5U~3Mz0T{2Z@Ju/Ox5YC^;R9K{3b3[|0Uz8YCX>[?`*[/W:P{;[GeCd>\@f@\;D|6^?`_~6SAS7\:[}6\@PA]=g?W-K2Jv-V{@Qt:Nz1P{>Z~;\}6VATI`9W9[=[9W}6^|>X@W|/Vz-S~3a{1Pr(Lu1Uz.Xz.P{/T|:]{-W{=No*Gj2Jv;Ms+Su1_w3V@Wt+Uz4S?P9Pu0[|6\>T}0Q{&Tz/^4^?\?Z~?Zz7V{5X~4Q~1VAW=Rz7P{9Y~:[{3a1^CU~3Py4_:a;_>e-iD^}6a~-Ox0`w&_~4^u1Pr/[}3W{1Ru2Zv(Zw1Mk,Ms$Or1Ps0Tw6Nm,Kv5Jp&Kv:Fq,Gh"Hg!Gg#Hi#Cc"Gf"Dd"@Y.G.E+: * , .C &=%: $'G/U7P2Q?d#Cg#Mu*fG_He[T!H\$O_%C[9W;M4CFU}Oe1AX)0;#),7CFV6JI#AR31L&1S+Hc98X(2M#; "C?'0!,29E#Ld/R_);],'@%(@$%>);  "0+J"+  'CEU(6T)'    + '#3D[.&>!#+4F@  %4! # AE%D#% 0,I0 . $  *#=B B D&P'#K+M&H?9 ( " . 2& /-$ #+B)@=(B* !B@7@C I#)S"e+@i*?q4Bi7Fr/Gt8Fl/N~3Et4Lz@Bv5Cp3Pz5GvAEyL|>W~9c8Z5Oy0Q{/^6e@\?XBW>\L\I^I`CRBY9XF_@Sz[>Vu2Lv,];Rv6[y:N=`?ZL\Lf>d8]@Yz3[~4X9[2Z1W7^1Z8a~7\y,Nx+[}3ZDR}3a8[1]lAa6f?e?e6ZCX~;O;S_^{3T2`|/X{FSr-Kp3Hu3Vv1]u)Wy9Sw4Y{8Y{:Xw@Nw:Rv.Mu+No'Hf%Mn!Ln(Em+Ek%Dm.Fl(Lx:Jf"Lm,Jm+>b @i$Gi$@`)Ip-Di);X#3IBR'JA+5 (   .* -<E_!OsuEtFoGiJtPkCwFvBUAh;k8mBc;]@]Gc:Us-]l/Tu4^x4Dh)Tr8Yy1d1\p&Ur&Rx3]}/]=W4c5hCQz9Su'`7Os'Vs6Hm%Sr/Xo(Rt0Nz1Lg&_|6Z}8Rm!Nq)Xy3Ur(Lt/Qr&Mn.Hm'Qs$MeHg"Vx0Nm%Yr(Ul Sz@OhIe&O_OcL_Og#La$Li%KhJ_De LiBd#Hh$Qh"HdOj$Kg!\x*Pl"Xy1Rp,Lm,Ri*Ui&Xk+Tm*GeKm$E^ >Y#6Z?S4IBT$5O /M=Y:_$BXEh1Cd-AR)CY4U!3L?d(?_!Ad$J_Jj'E^"5SBd >`#S}=-F*A%@ =E%G1L-N*K.P7V 4S=X4PFYB^!;\#6V7Y>X=[#=`'D_&C\A]"}_aOD;#8L=0C1@\.erFEM=PP8@N4CP;S`R/3,;EP#;-2L8;M1;J#7J-%?#IS3BL*]aHJdK   $7/9B & @G&2L!.>'-?"(   $CV+CO,*23556 '5*D 'H$HM(2A"?M!3J$ 3"4L07$ ,:?J  #&/1    )5#@'H !  "   & (:!@#BA) $+$G#+ #" =9&) &:F2-(   * <5, B$J%4    ,)L!)D(:(G"B(G,W$4C&@7-G . ,)H; !F&F>9)3/ >1 .1+ A&O 9>C ?9 )@/FCR#C;%! *'9;T ,N-I"N@9 5  ) 1 *6 !G#H?$D'E0  0C%P#"J #N"'IGe)(G 6#JCg,Ge2Id6&I&5?+I*.S#5b(;e1>c+7g1:n6Gu?Jm/9k72a)-i<@r/Mz^;\>bBTv>^C^D]Ab;a;e:_E_:ZBW{>`=]9N|5]x/Y~6T@^}3V{1Xy6\;d7X>a?T}:ZA]6X~BT}Ge8_=]|5Xv4`w5Nx2Uv,^5_{4bB`>]6a5`BV2Vy4Tx9Zz0`;f?g<_AY4]BPt8VATv,Vy6QuV2O?Lz:W4Yz2[@Ov-Jt8Su8Nx,O>X}1a;XCY}Lv4\x2`9\BZ}:_BZCeAe.Y~:X~4[9XB]C\A]<\}9Gs,Sy/Hx/Sx.Sx>Wwg';e+?l1@n.Kb'Bd,>a/cy=@a-/E,B&@ .$!  ,2-20=0>A^/S{DaIQ}Ia?ZAeAl:a|2f8a3d/e?dH_}Cgv5cC_9Rs1Su,c~4Vz0`y.Wx;d~1j~,m~1k5d3_}3aAi;ay:b~4_6d{&Xy3`~Q2N1G4L?S)E2V,G7K5Q9Z$N'L-I7[Aa=Q>0 9E5B87DN+G$;-   $'15J-M"/A$:% %  $ :, $& -1-9KZ%)8)= #*  " 5"9&?( %#. / !/ $4 " "%7Qa(2D&5 ,F1IGY"GZFd)( ""?1% !%7 2ICP%B[&Cu?Bj'\s1Vv:Ls.Pv:XyBW|5\>i6`~:T{;]_CY{.Tu/Zz1St/U{4U|4\q-Uz1]=V;\9T|6Yw.Xw1Tx1S}:^4[{.[)`5j/k8qB]5dG^:hCg:[~4X{4W?a.d:g:[;b<_=W~.[/k9e2a3e>^6_5W<]AZz0\n)[m-[|7[~+b.b>_>j,d7_7V~:\<^?]4[x*b;a8X9_=`z(Z~AY8[x3X~5\}1\x)Z~2Lw4Sz:Ty:Tx.XY2Wx)Q?_4[}6Oz0V9S|2^C]5j<]:SA^=_C_cBl9W:[FX;[9a@\}.^4Rw3\3]2`}6Qz-Ns)Tw:Lu2Pv+Z~2Y~ARv8Ag-Pp*Xn%Wl(\u'Kl(Qj"Ln-Of&;d'@g$Pi,G]>]:_=X@]0Z:[ =[ ?V#=W2J7G#D$/". $=*  %) -;)-   "8/1SGdZu6a~>eHgPqGdA_5f3[}1m1_})`>_v1X};Pv2Y5Uu&a~;e>^|/Xk,`|_-AOGSGXD^?Q ;K]3L 4]1P;V6Q>_5T=Y!5Q <\0NA[DY=PAX=KBV!1PE]>[!+H=Q?Z9PA\/N5K>]!9\@Q9L7N3Q2N#H$C,M!(I%B+D1K.=,Cy!)( #/,07,)"%:@CD-6*5),(! %/; 55  *1&./.   DEEJ&TM$ ,  63HD!XS)HE!-/     +-1?$HJDD!61@A&EK*BC&=N#(49!) '."06:LZ)TX3?D"-9,@F,"( !4% 1/0(;:M)($*.,=?3HFJ%1@*=<:&"$#(,    /D,*/9%7(9:H/?4GNg.Lf2IJ BW3CL! # !9 B(A+@3G"6 /E@FXl6W^)\U$  ->,A,5JZ/$@!; A <"%5?"2  /-K#2X+3U*9T&Xn@@N 9I";S#ES,BD !  $ #17?' 2 .9)1. (=!, /7+=Q'B`+&C )#B*B$!C%0(3@$9 $,8!" +- .  "?X5G@5BFCGN'Xc2LP,JW.JS$LP ?MGY)5FXa1cq2N^.t\Nd,\e.Mh.\rE@Z.Qd1@[-Oc4Hf?MvJIqgyR;[@P};L|8O>X~?Ly=Mx>X;Uy8PH[7U@V?]CX?Y~=Uz:V}:f~;V=]?\}?WBSv-Z4Jy;V}3XwV{>Oz6M~FLy?Vz;X{YFPALo6Or;YyDY~ATw.S|3Ff&Tp.Zx8De.Dm/Ii-Bd+Jk17])3^(7V=U=h/=a*?a'.[@_'=\#7W":X#1`3Cp4O~>R{@_Ek>S}EeA_?[y3Ws.Zw0Mn-Z~^&Fg#Di$Ii+Cc FcBf#Mm!Nh Ii)Cb"Cm+Kn.Ji&Zv-LiOk"Kg$@_%?`"<\$=XCe#Hd#Lg Qg(Ik-Ed$Nf"On1Qk#Ee)\`Rr0Gb&C`%Ii5E^#Gi%Bg#B]!>_$E`:c#=_9\"4Q A`"Ei<] Db"FW">X#Kf#Mb"Bb"3]!=a!L`C^&F`%H]"Mi.Ee#Ah*>U9N?Y>Y.O4Q".P5S 5P+L6N7U8Q*O!-KBJ$ ! /4AE"a_2MM9:A6NCJSU[(da3\Y.hP"\P WX$/99?:( >GBG*=CR/JR,PZ#jc1ro=IA%GC&& 8'!  %-.1@L(a],OU)&43+>7<8@P)GL%RMGR)\h3;>BA%/0   0& % ! DO 7? %8:=4GM#5F HOO%YQ0LS,[\&HS!JN!Xb.MX)`d0dl$M?!PN+]I%efGMI)H4MC5%  $   0# ! 16E1YH!LG/" ''K9;=8% 6 ?6D9C:ACPR.*+TB WG)D0cD'H'08&-3=S+7@@[)Se4K[.;H"6O!5O#(C'9T(,G!'B,F!)K);:.K*+B!,C0K"1J'+@;U3/P%):'?"&>"9&@!$<"@ :7/?:8&HB#8$E#B4L&.G&.E/ $9'>??C@4 <$C0+ /-7.<X5N6NG\:]$>[@T=^?NHb =b Lh$Hk4Gg#Gb H_Mf!>_ Ul$Ld#7RGZ?R B_'CU!3]!9S>V2R;JAY5U:VF_-R>SEP8J8J .:7P$6U#6U6R"6V6P#@\$:R!:P:OA^&}   -+!.+,1>>E02/ (!'/. %7        8,     '# $ (- ) 6;$:1#==0KE,HC$ki?e\?NI$9,6/;4,')&.;*?8??BO7BM.C:PL/$ :;:0 ve1jj5b[%c^'dX"kOyn'dMlV2_J@& xW'ol?ZV;<emIfUnnDux8~p=2->730 +&,,BH$BH %. ,%>=FLX&6+ PR04?1  F4 UK%%!56MW'ak?NW()2 -'RC!BG@2 "    BKVP!NH82>>!" )AJKL`e2\vE$?F08=H(@D$'8BG !1)>&# ! %   $   !   #        +  &>--971-   $2)%%>O!6)?=6@DZ1*J2*N#?j'Am;Nw9Xw3_{8Li,Om3Gx9Kj$Li!Kk)Bi Ef"BbF`BZ @_+Hj+Bm%Fq0Gl,B]!H`)H]#6?0I)D#A"6 )9 4;        5@ '1%//; %:&) @M=W=i"Af&Hd Qo35`2Ee*Nq3Oo&Mo,Os/Sx1]u3\}/g3Ux/T{9[/Rt&Lk'CiWw'Vq(Jk Xq2Jj$HlFjOr%V~1dv*QpLhSj!@_PoLn"Tp[r&^~&OlWp"GePk3_"Ip'Ol!QfIf%OdJeA]?UJfLo'FeJdKg =Z He!:`!9aHfMrPr(EaAeLaLl#8^'Ef 7d$Dh%"-S=-W;K1B1! )PD$dJ&:'.#ENCLBP3G/?.9;C>8$ #+%#*2 ,)<"5;/F$3H&89N?X"6H.D,<6M$% B-  "%-AU"A](Ae(B`,Gk=Kh.Wv2Vu>\{5Lt3Qm0`z=Lj5[u5Ph)cr)Tm*\v7Sp'Rs3Oj$Pm%Il1Le On&Nj&Jj+N_SlRj!Ml&Fm,I^!Pb#Cc&Ji"De"J_HbH_O_Qb"Tg#Nd$Gc#A_@a D[HbI`Og+CU!7R.R<_%Cd%=_&AS8OL^#?d'?]#BZ@`FS>V(>P6TG^!@a%:]?\2KDUGR;R.E)95E-L-C$D/F1M 9N BJ5J6L2K!y#  '*$ &'3+" & 4 ;22""(( /# 0+$*   0+        (")%)-7%5?9CJ?GB-HJ3SD*8DC#"".&.?4@NA?B6.-2>:90F;! ?2;)D?" @3XG- ' '' J%M?M9ta*t\(M. eHK( b< e?Z?xR-bEkOu`'\HOG!MDNE`]1nb.i]._X(-006$=@)DO)*! 6EB\<844A)$ #!*." " (AB' $$* !   9* 1 !!  !!?& ;1 JU'&OK 9-PGZJg_0kj7tvHIDSR7WU2RM3*$!)'-+&-9N4%+&44E%>(.1A%2-+MY; LB\G#gX-xjJ`M*G<"   :0 #* "  "8B :C%".    $  4>#  )  / "28R&?U*5E!@\'8\E3SEb-/Q!@c*Fb#Gn.=f-Cc#Bc.Fi3Lr4Im/Gi.Ee)Be,Ik&Cc$Hj*Oe&/D+B'/ 3 .B 8A 1 .>#7/F2H"1*:DPM_&Sf)@Z!@\#<[$@g)C_CfGl"Ki LrAMi+Mr1cw3Pp*Ln&\z(Wr-Wv7Hk(Il$Sk#Nh%Hc!Ad)@d"BdG_ Jf Hg'B]?b'Fa@cDi!Ik%>_F]=X.I0L/Q4YEeCaD[<^9ZRl%D`&4S=bGgHdBc!Gc@TEcBW1R1S0R8Q0^CW6Y&I/S4Z/O-L5T,C-H0C"D%G(E/H:L0K=O *&%*  0* % #:53C?!5*$'  "   (7+2,  )  %"B6   "(*- '"DGF8=**/"(.!5:/ @A1SI6<>@4A?./+/.9,2#=$M+@.0" (-AC$/, *0,<"(.,   $   (25?#     & " !   SD)M>?+% G'0B)1; MM2P;&NG+80-1@[7B\";d5>].?_,B]*Gb#Ld,Gd(=X"4W#3R>^'6V&4O")H,B4N0J3F-C,A,@+K:O#3J"3J1K4E#? -?!@L;M2P;G6X*0L7W#-I#>M :R"F\%>Z(B\"Pl3AdCG^56M#?`'OgJh(Nh'Dc"Sc%Ee+Hq;Md-H`,Sf)C\ De)Ne Ed(I`!M\ Hg+3T"?_#Ef)A\7UKf'B_%@^"4O3MD^De(@c@^ 1K@W!AQ>O#:P 9N?P0M6R3S>M/G$J*H? E 'M$C&>>$>$='08#A-E'9$9.=9N).H'0I     ''',*&8)!@: ;! :*UO*54%!$(  & #  "B?#   %C.,    #     "('" /2!  ,*!3;>5@"A0(>BA". "//!0$I4!R2 ?45! $ 2$8#* ' &">" + D70 )!$C6+' (r^1pR$4N:R4bI$\B X=iN#L6 R=M.aJ!X&cZ2`M!XN!RGB8?;M<QC `FaBaI'-,3.!#10@C3  ! *;  '**   (*37 0$  %1\9C3J)9% 7%   C( ]L&W>S=P?"JB$=B+'1  " ',/+*7% -& (+JO)ReEWlR_^?/,;@&$-DA 35D<.&6/@1E:B6:3@99,:+3&G?:'1$% ) %&1'1$ *+'"          !*% 0)  ""!      ($"'       2257),1)F7![M,IG(B8";0&##&+         NLBORC\]:JH>BA3?60><(8.3MTG\_;LM1B9>XW;NSDQIH`MHbQ=SROS27C7J5@R@DVOGVO>SM@S\]5N,G,P5NBY)H;Q1F'H -H )D.F(<2B5N#92H3M6Y%:P1K  %&")$ 7C2:0$('9C-36!87(        +.E5!          .&"&,8% +("*#+EI+;11<6&:% /-&$.&H?+>3) #( 5 % :)" -% 13 4" ' " bL(K+.D5K1F2S8D,R92' @*F-f;N/Q<NI&h\/=6/& WH+?,\EO?'TH"A7                   #-%@4%  6?-W<I1D9.!,# $9) 7#0(_H\J#PC$UE?:/2      /     .*$=@.LS5M\;:=" ,)*CB'72+0!'.(3.?90*8(.2.*3,%,0#%#   #&1.  &$          "6/                     "!-  +8+-(;?*',%-( # %"     &6% ,<$67$$.C# #2*5>UD!7 '% )8 $47K.-9:TD                       #  "          %      "      29%$$)# -7!EB#% 1/IH,`nYbflM`r,<4 -4+0D[AD^z)BY  (/8"??#D_b:@N:GO3BP?X_;IMIUI?V`9GH?KQPdyO_eGb`GONAKRBXe.HW>OT5F^->(21=P\7LZ8DJ+HS?MYNQ5LWHHI5BH5FTEOS;LP1:6+2+9+&(&/CP%/$<422/'7C2M]`;HD;CH?ED;EF2BF<=.5C95EW.9;3E43A>)1,36 ,:4,4'/04A55*B63J6,I':S)8M!AS?V#;[#8S?W?e+=_ If"G]&Pj)Gj):^,@_(7c*6a!5Q/S"`%,P"5V#N=F; =3               &-+L( :")" @B' dW I7:# =]A8&8'C5 XBiTTERG)/)&$        !('%&4@')!9:;9#' .*-+008:<(1$-#)-/8.#%" !' " !#!             !                   &$% (             AE&&2)4!AG3!/@A">G-4H2,& "'% &+)5 B;$                        #$               -5& #<#% KW:$' 8?2EE364%FMA,:$8 ;;"SfmE[f?MP /.6H1@M3Wio9BBP[WNfyDdy-88IXHFU_H[a@LT?@P=BH;J[FQcP^a@Xl>GJELg5MX=LJ?S\?T\7ETAJQ3;GAHT4AA$*&6<3CFPEKNDQ^B>KL,?DBCG@OZ2GV6AF-<3;GJPcMS6FH=FF,%$(**(26*9$$($/"  !& 5-)?%3K+8Q'COC_#BSEV!8P5Q BP4O.C1L$P,I,J0M.M9L+H%G2M+N?O@Z&2R 1M"2JBUOe.Jh+D_CYE_(Kc$L`-Jf- # &")4-72"01(BE'MB#MB%SI0DF*'.!  (        %'   ;.)) )84.$     $3)!0-;7$]\FbT4:@/"77(&% "*# D.- 4.% J6&%$ ;) *     ;8B2;% D1*'#" 8*H<+!BM4 L8K3R;KDSH)$ "!4,>&R21#  $            " "    &#!E >% OD??8#," +*,#C?A>HBC1 L6< H2 D'PG PH#C?0)**  !        $ "   109/ "& ) 88!/2)(%1&#$+)88!" &                         (    ,*           #            "&"0F.$, %2>#/   >F2&  )E6                    "  "5             &" *5 ,  &;6C=%/+B'BW-QS=KQ?@HCQRCFH5AK1HS3ENDOI=PL,?N;@B.?G6@?4HM183@CHH]`/>D7KT:=G?DG?ML&2A&%5*!$%(/2/%C/EM0?J5<@033"03#55"34%1D.:%* )'&05  &2#"#!,- :'"1&8C7N)1D-D0M!(;":,N&4X-(?5L3N /N3V$+N(9M:J(8N%/L$1P 3K3K6K3Q#3T"A_)@b(;[*>Z)E['K4&/ 3/)K. NE& F#T:ZEK* K8TF#[G- ##;) `L'O)B)                  $ , ) ?%1$ .E) E0Y?!\K$G/7%;.3(0& D9H3O>"P8Q)M@hOlJ+]*kW#B6 "                 1&!"+&*&'+!%!#%%"$")%# %                ""//(%!! !" !* !!                  ! #                     !     $  !          &. #+"! ,/:Q: :?>:1;,V]HM\HADWFPOViq_eu[aqfr|^qcx[h}an|XfyKQN8*&Yc`Sc{.(#Pek]eoVbrO^t0;S)'?S\D]GHa`O]\OcuMWsSgIOfHck/:+Lcv@PdAPaT\]GRlL^zIWcEUpBTjH_pHcl>NTGYU@JWHVbAPk?OY2K^+CN.?E4Mb9IX-7K08HEHLCTg7I\2?H:HT/S=BJ.:C3;H5HV@HODGF<<@5?C6?C=DC5HD;AL:BP<"/K10K-8P1*L)1H*5N&8M1%;#.A"3E&3H+1H!CS+=Q*[`G9HO+>KFUH*1C*7B"% *4?)(#%      31+$2,2*2#K4N=?- E=F<       #  3@2<:#8B.'%)<:23!0?8"$ !& ?:ME"`CD7CC1,-5=+&:* @3>.*. #" ##,>'>:!%VF F;=5 9!J. O3P?YII<*# G7N?=1;=             *6$$(%6. 2& N5WBA, ?#C6S;P: ^^"K7 0+3) F:S?^H?*hO!C< O?\;jX._C#y\?eW2>A#$$!!                ! )-$$)*/!/&! #%0!%% %! %        #!"%$& "    ")   !"                                 ,             %) $>&$$ P_6@LAMGAX[?EFANX@We=NZ+7L4FJ6BEBKL?E>?OQ7CK6?9.AB16G6=DCOI8EG+<3@HLDB`?MN)HR?SU:HTPZd3L`3@FBCIALS=>;5EB4;?@IL@HQEP_IGMAIL:BC;HO2;46BK3@K)1C5A>;GR2??*9/'<0)8@)59,@F"/"!#&$" $!',**  !# ! !# 1"#(%#%&0)( 2C@2B7*)# /&&)%*(2-"/.,2.(%%-%%&!'#(%-( '-.%8*? %31?(4?'8G&BN@IU01H"9T%Ks%Ce(H^=W2C"9M*35 $= 0&B(+ '& #    94#H/f_?;+A2?6%             %%2 &(6)?K'.'()5$,73/"/1'!3.BG2\S*h]KQI/;8(HC( ! !>A.C8!B3$\F'\T5<5 # )>+:,8(92?)?*J<N7Z>J:-'A=!XA#<'-&. B+dOS@TG 3#   ! "!!                  9,<;$=+OB&OF,B8@0eElS,oU#|b4_O,8 B+N@mV5]H!O3O?#MD%7!dF&eR,= mH+eP4&&                 %*%$9*&"!#&##)%!" ))*&" !! #'        "%&%     "&!$#   $$(! ")  # !/ !%,                                         ::1;2$24NdnFV`BLG.6&>?:/.)V_eP_ncdoWdy8BQI\gdghuQ`Zn`pdr[o[pYk^fwW`mYguRl~Uf}PqZi|Mav991"(,GX\Lc{IarMidBWfQ]jITkAUlNTgHUg1<;8MS=IN:Q\BViIbvMDNELe@L]ISi5P^C^iBWjGUgKRdAS]DGa8CR;Fc=NV@Tg=J]Vn9JY@GU>L`8GZ.DT7E\;AG6IUG]CM]AMeBHXJTDJR/Ib3DR7>I,AE0AQ )/.:C.;H6G_0;M+K 2#!$,67&5(4B+2G#4<.CB$,$4:G)/-E&+='.J(9N'@H1I_&DZ0OW8Ib,BP5H1G$:I.90B*--17 +!5$-%4    %'  #"*)$"                 #1-  -1 !+9)7/-9)>:07>1-+,+."$3=9#  5E8NFdL!sd8     0&               " <)Q?!xg>oS$^?mM,yU!]L f[/yf3dJS:jU+hV'PF$QH'=,Q>S@VDXJ&WJ)U;%mIC>2$!+$                    *%!+5&#,*"$(&&&&$'(%'"*  *$#    # *.$ $(, &40)./*1%('4%*$ &%   22$'$ "%*( # %.("8E#$ "$###"'"#!*!-")  "                               '0/6/1;::@4HXZ=FA;MQ;FEYbbAC/W`b]l{Ll_hYsBRTeu~^lwexd{]l}WsNe|YmxZqr_myZ^d\heXfiO\i\lwZjObu4:)MTA_oQbqTbsZd|S_iPnGVmK]rHZhE[mHUc@O\Td{HQZHXlM_[LXSCU\?]lE_mF`nL\j>NiARgIRbASfBKPLOV@BKAKR6CTBW`@FVAO\OW_FQ_CNT?LRIIL@OWJao:KW;BCIVe>LSDPWBFM@NSENTBLOBCV>A[JYdKO_SYbU_hCfRfF^hNbqGRWOPOMfmQ_lN]wK]_CXjIYqGSfCSUGRZKQRS`lGNS;Nl2AJEP`FR`?GV*AL-0C,4G,>!+;&2>&6C%7D')$,1!47'3*#,1$,"&&4&'# (:0:?(9!"+5 "+"52/:8*('+#((.!#33 (($.$*,)/, &.3;4")>%0%&!12!)**?E-:H**6)3E#+3-7/I!7B5?-BO*BL(8E?^":J"B_2Sp*K_)CJ)AY=[&>P2@0F(9M5I.2 +5,:1H *""'7 "                          ,2"66.))KM";H$BG1DI0:63FE/AB7KR3JJ(?C/BB/CG)(&2.)-2(# 71)*$.%0+$LN@),$.+.())&) **GD-iXB|m:fR1ZS4ogDH@((& PC dL"3303&$ 6' T=F1TB]G$a[8'     )&H=!(                !)PV@KW?]I(e]=}lHtZ)WL%jX;xc/i]5`Z2MQ7MK1i]5;;*&(CC-]b5>?&F-mR/j@teG$'! !!            -+ !'#+%!%)-*. *$"))$'" !#)! +$ !"#!!' '"     (%)')'#!'#%$*()(0 #!72%$'/?&.*:%76%&2!!'$#",2'(+/#&'0$',01. &12>(-       #                              ($$$ *-* 92/*BA0BVRDC:OVLDIJJH?Pjx8F?L]dZbmZl}Xn\bfP^[Zkeeqx`w|Wn}MUcYdk_t~\gtbrOciWdqWfuVd~JgWiOcyZ^bKO@JbeSbpNb|NcyF_pRkuPXlK]iO`lIUq?LbI_dReiO[lM`lK_qH]eJdm4J`AKUJ_s?YhG\_BSa>QcAL]ISVC\]@JY>QYA\^,;-":5!'6$&)#2!+'$.:':",,$4&'(" !(& &%'&*1*% +.$!+21%.4%%)"(*()1%#*30'=Q"CQ'31$3M&:Q'8P':Y)Oh2AS"Hm-Pt.La2Mm0@a1?X3BX0Jb#1H/J GX"6M!:S,8] 0C0O5P+81<1F.A$!-:# &$'" !-"*'6 " ! #!+& !!!(#     (       %!.4"&!-2/HJ$;F%DR2J].GR>RY8R_0OI8LU0CN2>G>Xk6M_1LX)@F:Xh,88;>>0CK&36(62$7A+8/)23&,2$"++2>?"38*/+4)=0   M@'j_.GC1 "#         !  *0/+M?#XFPP<\I64&!.'&>5(1=5  0%KG.vgCpjO;C/"&&'#%%!$%   1 ##! "# +)3)**,"**,(.7'&$%+0/)0'()&&/#&)"-$#(**!'&)$&*#)& #  (*'(! %#.+ %" ",# ,;%)"&))5(/6%5A%0(&,"&*$,+.3432!%''.(/$&!* &.%))'$+&)%!    %                       +#!50A;1GNREHGJOHFOLFGFKWbPjKXjFLdYSjM[lUasWbmR[eJ_oEWhGXeP_pOdmR[kNdiIRd\epYisGRlHPQEWjKRaFY-3Q&.:0>7*16&;J'*)(9$*< /C'5&./$*-3'/0A7$, $ !#" ,   ! %   &"(&''$$,,!&  Bi%CY";b!E_'Ib+Jj-D\.Ig-Pv%Jj*R0S:T{.Ox8Pv-Mr/Lr(Lr&@c2Jv(Gl$@`%?P%G`#H`8K9W6V8V(G9S5K,I0D6S1J-A$@P7@/?6J37!-'57F-3./#0)60E*85@)1 #0 $ '! &$"!  ' ! ! ! ) $% ! .+5!1&7$@P2G":U0Ia3Qe1NY1Xg3Wr2Oe3H`;Sd5Qe.O_?M]),6) (  " *5*9+"!(##&),  !&% !"#!  '   !  $&!!%#,'#%  "!* -3&7;63;F?9@<-,&$*/)3 &"'& !# ## 0 ## # !#3  !&#.*')($)"")* *.&'*(16$)*/"11$)-)40**,1(!*+#"#!%)!*(,,!%##%!!!#+ ('(& ## !+ "-!%6$/5;'5',!-0&#*%!=E 1@!#%..5 /0!9B(0:'57@C8@)KPU8:2EUW8ABG\jC_vU_mI^aZn|Uo{Zg[l}awYvZr\jyUiyZiNkYlQrXkZl]odsVkchyJ`qMgwPdxW_sYfsPi{Smz[rSmEd\hXn@StI_IdyMaI[oPdpLXpJaHiMgL]zG\iSimXkxQ^KeRd~OlDawMfyHc}J]pJbLbL`C`sId{Pj}GfwI`jHWfM`rH^vFUdSayR[lC^sMarSehK`lDWrL]}J_sLauIc~G\rHcrLh}LddP`tL]kJ_pJ_rDZuF\eLXc]_d?Nd=La>MW?NbDNW:IX@Q[0AD,AN/6<(3= 0E"6 ',#-!$$!3>% 2 !#      "  '    #& )     ) #-*&-Bb)H`#C]&8V#Ep"Jx1Sq.R|0Eo2Os.Ux2Y/Wx-I-R*Jx*Ko3Ry3Ps)Os0Qq5Rw(Ik$K`(Cf#F_$Cb9W4R";P 7M0P2Q1I8J3K2F3I6J4K6K0@(@+C*C-5(D0@2E&47!4%& "2!/!.(5 5"-!  ( +:#3 6 $7 )- //H&.$45C.9 <'?Q,9"9M'K[&>[.FT6L]/Ke-NdH\r5Pm3Kd#- 6B3@,/,2&()*"8-5"3'@,"+ + !% $                    /)$(8:*(&0;:;A/GSNBIIKZ]NMcPeuJ_\L_lN_lYeoYs]kWjzZ\uYm\enZh|Vh{_y[n]fUfNayWlRt`uWfy\d{WkPl{ShPcuMby]i{MiO]sO`pLXpI]rH]sIbxIhLi|NgUe~NadFYhCMhF_rGWp9HbHZdB`CZjMa|ASnAXvHcwCgxA^sM^iK]nP_vI`vIfwCXmCYa@Rq;M^8Qa1Mc5FS=D]?FT6Sf@\i$6F 659@")+"  *     "              * &.!/  ","!-#%,Cd.BU-Iu*Hk.E]&Fq(Hp3Sq*R6Rx.Mt+Qz9Z}5P(Lw)Mq'Qu-Vp(Mr1Hp8Ko1Db2Ov$Io%Fp@h>b$Bh(&4'1)A#%!07 ?V";M G=["+K$;R(Jt*@[/Tw6L[4Qj3Os/WrBXrBaDYqJlRi?SoG]uC\o9Ol@^q8[v?ZoU/@W-Hb+J^7Pd#@J)=.C$=-&0+ # %)(;!2#5$+#$!)%1%-# ! 0 '  * $ #0)2-&! # 4(!&#$ ' ' # %$,!+, $ , !$ -2 & ()!3'!,:$'!,@6+05'"'5&;+9()"23+- %( "$4 !3*.*1 -1$2" /0.%./-''$*""-:!&" ,.:=8;$&&/8?.;C07$)>@&7<.>C(65.:6)1/",1$&.0#14'%$51&19% )+&,3.)&$#"')"% $. &%(&)48)8)!,.#,.A&- -4&*< 22":H!6: '/%54,C-F4B(3B06+;6M(. 3I-C)*,&++A 1A'2&)%3)6(: (+41>.5+1$ ) 1$ !  # $                    '29;<)+((DIG8<:J`BN_=IXE[e5FYR0?A$7J1DR2>Q0AR*O[+Mp>`~+*1: 7B2=03&1%. $&/ #.(6,>'9 '*< %"2-"*$5-5*1(7"0*(,,'-',$*.*6+86(4B2BF(;=&;?*'%-2<%94$R7?8C%>-K,H*?):,@-E&2+@1B)?+>"'&;1:$-)6!("%)2!(#&/) (!     ' $                           !-&%-&'-)74-=CEJ]3?R=Md4L]BOg:LZ4AO,FV0KT-@P!7M2@H.CM,BO$DR#1F.C/:">;!?M#.2!%.!&-(+56)5/"2*6!,= +;#"'.9"$' $ &-$,@!*8 )7 "'4%/ +" !                               "    5Krb-Kn(D`.Tm:Rq9M|6Uv>Y>\=ZAe;\=Sr>d7\Fe<[EeD]o?a?eC\>X;OCLm4Xw5W|6Li1K_0Bf(Mv/Ln0Mi7Ro&AZ*Fe%@\)CR3G0="(%7(#2%4 "'(%&* ))& )'!)' - +  . +/(7))(-#"#- ' +; %%3$   !*&#$#)!,%+$%;(6+B#+",#7$/ #. %':%1( +)".4&0>1D";L#;E&0<,).00?!.C-6-#1+9+>(/$.,8!.""(2(:$+$ *#3'-!&)7,, ,$*/2!02'0/(//+;>&;B*7='/H*?M$,3,+.,5-,/0(;E(19$13'JeANWBI^B\p7IY5HU>?Q+@V1G^'IXDJ\0BS*@N3DKZ!Ld6\>V@b6F1H7ZAX6PS3W#;W8MBg=PImA\$Cb+F_"?_.Oo*Ei%On#Mp0Rg1Ss4Zy5Rx1Vt9[w?e>b,Yz<_B^9bCg@_B`y?WuG`}?e3Xp=]:Rd5Yu2Sy)Wr*L]2Uv2Xr3Ok*Os.Pj9Td/Wq(C]!D[I&5>8I#:E-:M&8J!2C(5-G-;$3H#30?.6'9>3D3D*6"-@06&((+#/'+ !1$/ -?'&*#"$('5#/!- "*&/"& $#  "     +      &                                      z=[/Hv:No:Ty.Nz6W=T~3]y:Z;R9U;P}.R8_1Z-\9U-I3O6Ry,^/Ou)Or$Gx'Hf$Lj.Ek.Gl)Dq?\#Fm$Do"=\(=W"7iAk Ac Ah 9c&Dk!Cb:N?X6X4W%?Z!>[$<^%A^#;T!=N#?]Hl 3U1S";\%BZ!?Y#B]#S{;Ou4]6W;b?_Bb@^;Z?d?dHWrDeEbCb?XCVy0Xx.Kl1Px>Sr0Px4W-My2Ca)Ot0Ig,Hc'Gn'Cc,Hk4G^)=Y!;N'E'A!= 1'6 -%*#. %3 * (. / , 8; !!*$3!&,8* 1 ,&* -)4&/)/+%$!#"*$&&:"2% (&,/%) #)6,("  '% "/ &-/)>*+"0) %#),%'<7F$("/(-/&3.=&+!)1!*<%2!2)0/>!,$-$#$ % !  !$-!!+$3+ ) ()0&/(&#!)'(,&-1$0;&9@.;B3<4)74$A=#(+3?B),,%66!+3 +#' %"($!#'#%$ !&$($)%!!#(!-%6': *")'1$ "'&#0 .3&2#( + * ' #     )%               ".88,:='7H+8G-5$8C->.L$1$-3(<%5.A.7):*0%<0-#/+!/&,&1 #* !*!',!)%#!    +   '   !  '           ")              |=To6Pp-Px.Op2Po;P1Fy:Zv=X~3Xv4^za?`<`AR!>P%Ei;Y*Em/Em"Js0Ik.Rz)Gn-U0Rt>`|X{1Mv?Mp0Uw7Vx2X~+Su(Mi9]|&Hl.Gd#Gb.Ih&Ba2J CV-?'-$=( ,"4/ !.%) ! ." "#!+ &  "+"!*>##()&- !#*-*$8&1 ! !* ##"$,"% "$!# "#%!' "%6 "(%6(<#)''#!+:)."9$:5(:!1;'0(+)##$ -#-#)& '"*'##%-'2'.  "&#'&"#-!!-6!!*,"36#3!(($,!) #)&)00-,5<63.,'2%01'%#'!(*!&#(2% ",%% "!"##!!! !!$ $         #                                            &'&0#/!7?%+.!+9#)/$.5:?W&K,Y 9UAT-P#Aj!8]#?b6XDZ!];U!C`2\cA^?dDhDn:`9iAj!Ir+K*Ms)Ny*U.U7Y*Q6`1Y1`?`Bd6RFa4^=f;`x+Us4S;X}=Rx7Ox3W)Pu,Vv(Y|4\vIw3W~'Gm2Di1Mk'Ll%; 2 #8$+    % '4, '  ! , $   #"( $0 %'2') 0+ .  & '$2)#( ','"#- %0,  # 2%   ' && ! $,.< 0A#1;&1!%*07-4$2#+!,%0+!'&#* '$ $ +!'"(+3&( #&+(+ #&#(#,+&1>'$"9:,1&$( $,!!2=$# # ""! )""*/       !    $           "                 '"/(3'9 *#2!''; ."(#1,5 #0-&"2", * !< #+(0.%#$ !   "+)  #      "                y@a._4S~4P8X5M{8Ou4Rv7S3V2R|9Wh%Cc:T@g A^Af ?U 8X:\7Z%E^;[;W?\%>_$Cf(6X">k!@R)Ed U Fb@f!BU B]4L=Y 6Z 9W>^#<\;[7V;SGe>_&Do*Fn#Ad!Bg)Gj&Kj@dIm,Py%Fm+P,Ko6Z5[6Vx/X}1L{3YB\=d7b@aw;XBY@aBf?d8Ry@`-Pv+Rt(Lj/Vt3Qo0O{,Mw*T+Py0X#Db-Hh*Cd$>U$B`Bh 9M(7-C&3+!5"1 %"$ '  %  !       & & (##%&""'$+'%   &  !'    " . # *  %& (&'&' -5#0@ *@'+",:*7$))'5#!&&! % !'      ( &)!#!$ #%"$%$#%$%$"%$%!!$%#                 !   )         (   "                %)+3 ( . %%#+'5* " - $                    7L1R:W}.Nu4T}4Ps8P~,W{,VB_7Y:NAV7Z9d1W-\3Pz2Ev1W0Ku3U{,Mr+Rt*Hs)Mp-Jp%Ad-C_.D^$Em$HgHj@]":[!?_:Z=]">i?bA]"c!?n$>\+e%TBg"=X#?S5R5W&BR"d#Df%Ds%;Y7c`\[Cf"9R#9K.T!1 8'!$         #                                 "     ## %(      "     $% !#!$#''( "%                                5Qy8X|A\8X}4W2W|5b9W/R/S}3`+b4c7U1S}1X,P&Mr0Qz4Wv3Ss*Mp.Or/Nv&Jm!Dh-Qk)Kc Cf%Fk'Dg'HmEi&Ic Fm?j@WFf"BV @b!<[&FZ >a3SCi"Cp%Hm$Jb&?b&F\=\ CmAb%Fk?P#Eb&F[9OBd>V=Y]=b7W?W9eZ#AW.F&)"                                                  !                                                      0Z.Xu:Ut)b0R/Uy1V0T,U/R;^'S.U4`1X~5Y1W1S+M1V0Rz)Su,Uv0Tv(Hp.Mo$Eg+Gp :j Fr'Lp!Gi$C^"Cg!Aa:X;fCiEkI`FpHr>e#=a$@e ;X7S$Ch5]$Cg>d5g@e$Hj Bi:`7[CcBhEi;[;U7c>L9Y?f?\gDmClBl;[?d.Lm%Lx*Hz+Rx/[,U(N~7[5a3[;\q7]7]9_)R5R+[/Sx6Lq3Lr,Ku(Pv'Sz$Ly$JxDf$BY'Nu#Bd"DhBkHsAiFk@S7M+B%?(7#,#                                  &                                         ASv6V0Lx0Ty5Zu-Pz0M}3Yz.Ls8S<\+Kv;[:X{)Nv3^3U3X|4Qx0T2Nz6Py4Mw,K}'Jo)Ei-Im,Il"Kj+Hr)Ho;f Am&3]$Dg%D_"=^&a"@b;c'Em!A^=Z?_;W";[3P2P;[$=b:e1N;R!7Q@\)Be$6S1]<`>\6TBf=f#?c)R;\5V3Z9Z/VZB`:ZBc?`bBg Fl;g6X!>c?U;X6[j4Yh?g!Ku Cp.Hr'Ms&Kt P|%Np'T~*R~0Y2W5X+Nz(P})X(Rp/W)Y-Ox/Qv#Ir$L)P&WyEl=aC_"?W\ :T&2W X3\6Z7c:gBg%Bd6V1]7^>a>eX1S5R,R/SFU.M*P5P3[1T :b0Y.H5V -J0Y=b6T:U6X1R0Q7] (O.R6W8SAd>]%Dd"6]Dm&Dp)L"Eo(R(Hr-Pp7S{&Dw'Ov-O%O'W(Tt!Gi-R~+N3S~&Ju&Gp$Ex"Dn(@f Cm&Cu!@]>VBd @]<[;_@W5T4P7N'E -@ "8!                          1- $/::#)0"# % #!%    #.                                      9_.Pj*P9St-R})P},Jo0Uv*P3Ju9Z8U3U*P9Z-Nu)R~.Uv1Qp-Mx#F}(Ks.Ju,Tu+Lo(NnEk>j$De"D_!=e7X"Cm@h6U6Y7X2Q1Z0N2O6W0P6[5U9X:X7\2N2S4L3L;Q*Ol&It)I}'Ny+Nr-_.Mm3\9Qx+Gv2K)Qm)Gt2S-Ww#Ki"Fc1Ih+=_?j:_ @eB^;R6Q/S7S9Me$AY Fj'An!Fr)Mu'Gh&Lm-Pu(Gi.Ws2Ry2Mm$Kx'Ps.Or$Bp%?].Im&Ko)Eb$A`'DfJqAb@X@:`?m!:N';_/H<[ S&Jb$Il7A   #        $$&      !          ! $                   +#!!#,!!'%1:     (77!%$ %    !     '                                         )Oo&Gd(Lr1E]-6]1N|.U0Y1Y7^-Pw4Wx7Q.W.Uv(He)Nu)Or)Jr%Iw-Fl!7R.O!?_">V4O:U:Q;J3A,E2O): $>&D+E2K):+;8%<)D4L-W;X 9I?K!7C.J'H-@9+F3K+E+@.D4I(9 &@;U*D 3M)< "*%: 8 A.H )K.M(D,P)Q/Q3[3U5X5aBeCm Bb&Ko'Ho$Im&Jd#Li"Hd-Qw3On+Wv*Ic)Lj&Tq'Nr,Mk,Hg(:Y'G\&Eb$?W#@g%:N;\1S*P8O!;O7L7HWHeCY 8R%         )'!!0'.(*&"   %         -%"!%   '! '  %.(%      $    &&"$).$".67#*(   "#,1-6!)-    $                             Cm'Lv-Pp%Ci*Mi'Ij*Nw7Pt/Lu4R~;RD%V0]z)O}/Jt4Gs,C_(Jo+M`Ci'Di'A[AW$>N$3Z;`/U #= (L.W &H*J(N!I'H (K1c0P,D8I*A)G0M ";8-L&B2B'B2BE*? (J)M"G)8 %>'? @&? !B E!+ (B $:5!E!D+W !E%O5Y)C 4J6>4Z<^:b6U#:b<\$>Y8T#?i$ClDf%Ls)MqE_Ji&JiGn#CZ!?_?j<`>h:\=`0T.T*F,G %C,@+T'B2N,K'C)K&        "                   '#' "        !#*/!"(  08 ##  #         !   &   #!     !    !" !   #          .> !                                  ,HX&CW,@X'?\$:\/;Z'Bk.Rw3Ou3Vw4Ty/V1O|0Su-Lp$Fg>hT%1<:X~B_BY{A^H^wC_F`{@a )7F?]u@\y@b~!      ",*#%"%* &         !,4:!$$)%$!  $     "     #    "-"   !    "                                   &:W7Y8X1O8X$5_Al:hEmFs#Gr#Lz Ix!@l#Bp! G H ;>>2 A =)7E+ &8?/2. ?54 ?458+#/, !2 ; !282 +, $,/+$!  " (1;3 / #06+32;CB6!;"GB@J B6+4 , 5"@          &        ;_{=^{+No%Sz1Wr,[s'Qx5\w&Me'2>[{9Wz:]tBcz>aFcw=bz:Z{ '7AayFfF]z *         *!  !!&% &     "%#./   ##    #%          (    "  . "$    &/                                           *4O 0U1P.S :S:j'F)Q7^#@s#3i @r##B = ; 1&(: 0 6 + :2))5* / % * !    !    "%  % %/  % )+  $           %' ) %%.%,#,,3&,        "!+"**,*%1,)    "%(  "-HR=@!O'E_'AR/1Sh^ GnCl>_ BZ@_8h3] &M !>#9 '>5#*                            !#),! )$(/ / -*!+$-## ' %            *'$/:2 !        G1B$3 !      "! &%"#&  *,C7$RG;NK@/"&!#                                                                  #/G+H"0R.Q!H 5Q7T*M7\!7N,P%@p#9b%D 5'3)      $* '!+" $3 #              !    !'+)3.'                  # *" 40<3(#     (( "*"%(O=03$+-+$.!'(%$  #                                     $     '                  1, "0+ "@"? )@(@)G"<6.#            )          &*/$-0%6&              !        ,))CI8.9&;3%@<(+-'$*#"!                   "%                                   "      " "  $    !1!,/  ))     # )# )#    !       $ $'      $# & ,0&$6-/)#     $??:($"   !'$"% %         4%='D>*?.# !     $!              "                                +2   &               "!    )+ "&!$ !!'<>;     ',%,=.*+)&-0)6;-9+         "               "2 F6#@?1DB:TF4H@'7'?A.34.(0::8/06/32:9ECH(;?@A=                            (. *-(B@2;)MIINJ=R=)C6:?/$G-/((                                               &      #      #"  "(!%#4&"" !"   "& ..,*)"$(%()%?@+;?/=.$>C5>>2bZ]RG3   "&7;!$#                 66-J?)HB0]D>\E1UC+YRQWH:B>2,!!                                                          ,-!#88/%0(!"!(#*!   #$# .:%,&"3.A3(2-")*')%6@?-.*h]L~vj&!   %B/C*1!& ( #-*7                     %5(A5,Q<+G?LG:XH,^R?neSbUGKC99/,                                "                 !%$&)#)#!+(#)"*'"  & -*!!+,!25+3?-;8"9:.,(!*'$:2-<@:jP&@>=                        '!4"6"B+OI;EF3\O-'@F>B>954.-!     # ( "!!)%($8:+B(!C::EBB% "    ;7=*!$                       *  5*&:6/G8'VB:RF9H/"XO=I;4[S?m\OW@<                 0D)B%C%O))Q&+W05`54_31V4Bg8/Y. ) $ &&.8    "- % -  ! # - % " *AA                    AB.D8,#&!&#=70!#     !.!  ++)"&*"#!" --+6:,((# )$  #%'8:386,3*"8)90%6/ 9/<7!B>/VKRWM??."0,4?.-7%;;..()'43&0!<8%*,559:'83$D=)HF5=:(CH,&..(-3""9/!C@+J5RG0;: +7>E5'@/ -&!*(=2%96%?=&16$)" 2*$ #%,,*!.+       # $#                  &.+/7&9=6KH+TW<[N9gZCYM;vfOl`Tk^MYXO        %8 8"#K& :#  5!   %*"> -C&4\+?d8Da,:e6=0;(.*2,%%"$ !"'%)'CA4/-#-*0*?/>1#H?&F8 ?GBLLGoPP?2.'./&5$ :% 4#"  30  '#B/1&"<&$D4:-'  #0$&0+*%9%&//5 75 2*5,!30 :-/,%81&0$ "!  $       %"                     " &']O9n`XdXXV:4bLAg[KvtYobTf]SO>5       *+ " +' '' &?3I!7d;Be;El:Ck8?l9Q);E.3                    02!:;);2!$! #)0/,)&#*!## %" ("+#  - .+# +!  '   +%! $>1%<="=/C>*B7*7.#?F.@?'A@.C?4KLE81$0%23&-*.<6$A@1E8$7&. %   *%B2;'?0"A:'@1$D;/CG/38)+)9;"3(,.&;-C-4)=0*87*(0?;&G;% ("+           $ +(                     %&<,#_PBSN>SB5]OOhXKUFo^MkeY       #''   3S$:U//[1Ch0=g4Cg0Ab)7]-0^25d/3a59b&F !)/   /#K?+:.7BJ"BU*  %()        /!61)B>)!#$ #  $ $   .&6+&!  (!+,% +$ 91:-@82'8#")    +*K>&&8%/6:A;9.:;3G@4B/+GC7-0!), 4<'-,1/#' & )#XL8VSA[VAnaEqW`QN        #)(-#1#$        % -HB\/9d26a3@`+@h6>a3=d-3Z$3[37^3(B!&;#$ %/!  #(0KX48N.$ HW5 3F)"1<&9J,   #     (9*1%8' % %.)!& #     %$!  % ( ' !1+ C<-.':5$08%.(;1"%& 4% #*!/*4?3&#&&2@&.+9=)32)@E=]WBZZZIIH*34<1*AB255"7(-$2"3#<3-"$!!%%0$&;&C?(B."8#B6H:"A9:/&C3$8:$)*I:!2, ;*7: C8 :/H=.P?/A9(:F6.# %*            )              #%#*!NY_-4+MD5XXLSQN:$D*|s\oZcdY      "%B#A!  J/ mYJ)     0.            "+ +9   %&440;7Q(Dc8Dl/?e49d.?c-Eg1=b,@f-AZ&7R#8X%!? <+ " 04GD   (1+ 8, 5/LW7   "'$#%       "% 17-81,8/#HTG_f[P]V8.% ! "  GD5 $*#  +! 9#<->774;9&*+3++%%.<;602#  +;+::=:&&,>1)"!+!-(%/-=AL`>SP,1!66>@B@9,3(!9+1(/ ;1,5<8   8<&3,?71/A;$?;)B=+8.:17*7+>2#A@1FG'@."I@,<6?/NC&F:$>.$KE2@70-#    %!        " ! ! ) $  +               6'CA*A55*H$D4P7}rXo`RuV4~gWY=vQeu_W[@      !       B@VK*B.:8 #           $@T!#$"'!  *-*:>ijdMT;2L-C2: 1   ZYNET O0cG9  K\4NB.;I7C?L=G=J"1;4I9N%=P!;Q 7L9T!CQ$2!&#    00.HTo  *63 '!   /F0 +     ,39ALH+Qf:Ki1@d7Gj5Cf<=o+GF>Ydp"&-cjlDB;.$"+ #, * Xag :"8$;&-'-*$,6%<9)?1%>5 *+ &':&*.>;5;??  4@1#!  GLVXD:585=/ ?379(5'!2)>=/;=? BAC&'*FPCF<3`gXh^GoogmyvN]XYcaHTV:G@Jsy>!%20BL[-9O$  *%!      =="DG7L]gKcg?8)1 1 '  >5)AH;EVQ()DQB9?.&&1 %%-2$:* 4-F9%<;)!%/'/.!/,!+EB%:GF&  SFHe`O --)DKAJJ@?B8@:,LB2DK:0BF   6ID6<$-0:1'>6*7;*:8'D6B8@>';:"-)2.;2;-#>.=>%>&9:$+'GC#QU?B@+,#    " "          !(#                           "'&+ !     A>'c\ColR}v\'!  &*.&  y\|md\@12"'&*1B;F!f.Gk+Eo6Cr4Kn6Em5Nm8Lm3Je(Lm1Ks>Jp7Mo0Fm6>g;Rl=@f-?^'*Q$>                  '-&C6IF# ' (.=.D;!H(K*R3T$7^1Df6Ac2Jh;Dl8Be-3G(<    )<#   # *2/B(**455>A5QX)Sg0    !*#)        "@9&QUMBOQOIA@>$' 1$-/%! ( )!MXT:3'8$;.<.B<,;7%:1!D?+=8&>8*;:,@89."B0"?< ?#D*dO3Q?J?*IB3=,-!,!?2)-#8%)     ((%"   "                    "           '    -+GQBlr[kkY + ' /#   {K~^ozbP9'% 9D#ER'Ln>Jm7Cm.PuQ#?D%8Q(!%2P*3P %J #C#H"I$)O"0M'[zlIP5# -AJY:&<-'"<"9='?<:#>"G"'O#0X%3Z)?].:a0:Y :_,?d1@b8Bg1Bg/No=Ff'Ij0Pg+Fe6Gh.MpBAj.Gi,Ba#AW'           '    )."2,DD#&- # )5#I#IFGA%M#0T(9_,4^*B\!.D'  *: !      %*(8#  ?R:(+, []4*> DM/;M)Rg8Ei-     $-$ &          % A:!HG?>HOIUGBA/ *&.*-"'! #6,Q_j$AB-80$@?(72!9)1*&#''2+)$ :&))0=39?1   8GC  CFH}xp *42ML=D@0LD3GK=AA:@D:;HN @B$ ' )  -('ykDdi(.85N1:`17a':^*']5=h;1d:?e6:iA@n;Cs;Lt;Ju>Hk5Nf0Nc;Kt7Ap=Bb+CY%?P 9P%6T%;U(4U(+M$#Q%*^+)Y/'N*(Q)K>+7K"*S/*R-=Y*7Z 8^%.W"&O.Q,(4+G!5T)5[';W"9W#0J!&+  (6$:! NF"CI!JP+[l8--27HP&O]/Ig;5d3  %($,*        <2C8#APNNW^00* *$;3-!*#0 =C>M_l)331(4&0$/"/&.(87!'/%(9>+(#/.+,&)%-*(-=<%BEG  B7Cx|&11GWI<@*A;6JRI1>=   ,B?;II5?1-*&0,00"2+!,1%@7%87";)<0<0B5'yPc8xaBlY:fU;[H.A?'9'=2$*-65 !  $%)!% "             #                    !            *&    &99   5lV?|]f/! -?^32^2=\+&7F N8(Q+)^,,Z/K)G#E&?5 '   "-1=!8 /4>C D: DD <"B&G(J&Q(%W,\*&]:-Z&-U((S,+V".W'.T*-X,5^17])7Y .T%7P%'H&6 , *77@?<+              !    "%   ,+# %:   # 28 :,"    *'$/ RPD>BI(5?@Oa8hsIMh.Qs=Ec,    #,#)  *(     !(#@N=E>- ) $ 0! % 273(R`W (+;HA7/0)2/3)111&9)80($+."%#)#+,3B; ?LH ;*/.'&GC7<4#G09;0@@?BG<@B5 HH!O!$X4/U),H!)H"!>. $        ! +<ACL(E $J#I!2R#+L!$B!<&+      '$" ->          " $ (1    .0(    ) ' :C&LP%&&23JK"No>Ia.Hd/Kn3Cj3     %"   $      9#=2@;':6(BPILC*I>&3#+.  !**#NZ_&63 2%1'1*96%84#?8"A:>-!%06;  #$ACG  $ &%>@:$8-4HHBFFC:ML*33BKHEIFNK9BC:>@3B?,BD;6?;#"%*6 EI<@1#-(!')#/10 &%#:/=(.%IE64 B,xfJywW_xeI5phQzdM]CVL,:3!-+-,! B3(3!% +'   "     $                                  "    $"  "   " 0-)      $ ]O?      %n_=iyxEA%#11@(:07F#<&2 !      # /F!%U*/^+2Y'=a.=_1:X-.Q'-@ 8 3                      !   '*6:%':.$          #+;$ //:?=8HB-'J=^_5KD RT.Pf>Af7Gg1B^1Om?D_6             #>*B4,'@&G:1S:"32)   .&BA?",##1#%!@)@+2%9%$?" %7& !65= "  KLN"%1-3,)*/BIFB<5FC0GD=C90KIG>%GC%;#(( ( " +IQE=1!(#64 &(/&' .& )%# - %*#* ;FG CPI#' 3.>##(.)KXFHG0J>*9.7-CC;BLL :>D?:%4**"  ""*"7!4+B<$.8 2*A0hO1va2tH1t^=l\4}a@zmCne6|td}kCj]EN?&A5+)?A1=:'!<)SA*92     "                   (  &#"!$&&$   $ !.!    )$aN2P0# # BH9 -/ 7&~fCeiy/%2:     &=J'#M!(O&4O&&A$    ,C G& H)H#%V) F2X,%O*%G%=/         "            '  !)  #'&         BL11?   %..  CC%I\5 4(AB&*$3$3)@8)D7$+  '    JO66%EJ2A8$<*">FDCKS."1$<+ GJ4x{]BW:`K{W9zeJlT/nfaG\L7fE1v]B^JES@;FA83$:3(L<0'     -,(4.$"                             " # #!/    .",($+'$    #&           "&  f]A~rjhn5$ ) &*,9$!w^vG1'7 3D%F%B&%E%/"     # 89; C#:C&J"L%G#==. '            /&5'        $'    &%7&2+17    '*%+.:$3 ",  ??;:%1. !( KN%M\(+A>Q(0I)(;3!A&3F'>* % "1 #- + "&            (H3#<:$:;OL,A;;:% !   .0 '*-$   5.1(/$ (%' #  " 73 5C?!" !$/*'XWI@4%?9'A5>=,BD<:B3 *B@9*70*!+#' #(" *"9/7).).&I5tRvC|^1_0nT.v^1wiA~fcP?uePYK2dT,_W>{w\bcK]G+:&D280   " $'       ! -'(               ' "+%     +& / $  !  #     &    ngCz|6%   5(<) & _i}EC-' ! ,=EA&H!5   6>:H K!AA> : 5"=?) %       !( ?58B"81('ID' +$ /4&8! *" #,&*:! '$5K(*;!;-     !           99*83!>6'=1$D;.(,D6 |e2~h3!5:+80%O9/)      ""   !) :&"  0"-/&ALP& %$#PF?B>C753#=("/+&) 81*;&,#/+"@%( :.RJ&yvMxe:g^=l]=}gueFvmMQC'\V;\ZFVZUx`Kj_OJJDC:(90 47$ULApaK!   '%                                             )6/%"30$      - '   $         ("&    1&.! $  .5)%#" r8<$   . 7=%,                  FF       #/GN&   ! $&    "1  %   "   #7     *   % "%           12<38*!CA/HNC     &$ 99,1)#""+5.?OD<8*B>)8;371."%.3,KF::;;-81&02&18= #!,#2)"7/=>15@1,',."&47)!#    %-#!.)  % ##2)3:*5*0&<'=&9 ( eG,IA#:&C93h7I#f="I.Z4R%l9#lS$"                     '#(      *&! *(#  "     #)%   . G/! -"=?)% n=16$   $ E9,          "!$   )6 %          %*'&##     ,,#'            ))<75.C@+56 !! ++3'3")+! $    0)!%    !!$&"% 2/6C>C*2)O?5G1!' #(' ;3!DD;-' %F?0<3>6 4488"6+?3":7,:/"   *'++:?11(;6#^YL]^D`bY`f[wxlz]ncKoNsiM~{m~`feGvpL{{hxzu{n6""     &  7.*#6)-*   )#                                    !       *      A&hL$   A++!' #%fy:7#       &            ,3( 2.  % (:.  !  *,   #> %  +)-3&   "7(AOIFMJ=HB(.!)$ 66(.9*1+ 15,"'$ -&(#%*!'"/'*(""!!#!)(%"20*>@9>A6DF5980>KF@HL=?DGMBV[S`\SM]R?I?DE;JE:88(HD7@=/:42?9%?F1FJCF<&K='F:+B:%FB/:9$300"$$%/&*- " - (%.. 3/$A: C<'92&01 BC?rlXAQv>lF|^Aj[:_[8\A"vfPywMeaDKE2NF(g^;neNqhUveM^96$  # # ' #+75 ..                              #'            =:4!@@)). " $;:,  ##0 }pIhn21+    %            4># ..* :.31 3:-& ,+@E @5OG!..119C 5/97$                           97<8".'%5)"  <2$0(.)0&% $ 1#",% +&- " & #'$  $ %)#"0) -%0%$3&)%&1-#;:&:/1&9.,8+!;1-EH8?A+02-" / 0"0 =,I2!}\n]>x^?cDrF[q`?iS4vX?uV/y[6rU/OD(k^LTF?bR>RD,q`H`;]R6$ ##+' ' )' # -    %    ! "                   '$+$   !  !       `F-A5* ! 4724  5!)d>zpx;8(!                  !   #.#203 #    +#   ,7-6*,03*? : 5. ->)@ *%4            ;4 ,)88!2118(1* 95()' 82$%+!#&%%"* #),.)66)5&$(&&)' $ !# '  &* !($,#%/-*<6*:2?9'(")$ DA1&)D:4jsmJND.:&-2&22388.-%3,:9 )3(    47%$ '  :051?/udEu`BiX/u\2}\3yf4o]4tcFlaIrlCqjIk`Ajd=NG;CG5<;8G@6;10-)"( FD>qxi_e]QRNXJGWYXOOEJ>.<*=/KM=NK8GE6TH;\\XXahQX]T_TDRSS]hNbdN\g'/"&$7/ " - -+3,'$,%*%'IE,[~xd}eGubIudHoL+}eKfFjQlS7qY=eP/|eBrQ-s_B\IAcWEwgRV-y^C05)-!! - + 9"%%0 (    !                           0)   % (  # 0&  %9$& +(. +-## , "  !    1'% (! 7"      ni[||~7("! ) *&'# K:#    =<+F=.I=9GB*yHFK>            ' 1 +!  &3$2 !    #4&-&0 A655-+  ! %1(                '1):$) $3-+#%#!+%&+#6/01&$") */,<- $'&"-,/:'$# @II;GIA^nBQR 1=CYU.;$./'$94EHI(7L&8C#*HHB;5 50!>2)7%:5,($DD;'-1 )  =PJ+$! . #;:-:,9/."2$G;(x_O{\N~dOliXp`:~_>aS@_\\$ SI8fo]>lO.iXGtZFp[N{Q3n[09)7"8&*3= 1%) *    ?6!," &     # (   $                  #."4& &3 5#!&% */%3#& +)/.  !        "   '&     LE0Z[Qo`Lx8%,# 31/   , a"h5 yFa5A?3          !;-   !    C5 B?!#   (           %)+>1)FA5@2/8$4$$&0,&=8/&.'$!& 0(.   2"%0" (2"8&;7;('* B>> +06 8;+ $ IFVB4(C1 A/"2%C3$@6(OF13.0 !!09A$5"&0.!., * &      ,' + )+$   &"         .' 6  # )! #) $ "# '                 /%%;/#H@01+=' " }X/v672           #"   +8"$  ((2 CM)>C"&( "&      #          #     " ,(.2#).),7!     " &%(*-#  %4-'$&  ! '=V\  .85 %.1$ FQD?>$7>(*%=8+3&93 A;"$*  0CA ':8-* 0($&%$" CIGPF?miH{\{lMyoPu\;WI1F<6I>4pfEmaEimPeX7`\NwiNqP8rW6 :$6( /* >/9&C&- 3( #    "# %   + %              %#    >'9   rW*v}lx*           ) %  : $&/.10  " !&            197'.* 36, #&#&  $* &$+".'&    ,''%" # (!$&+$" BGN'-5  *%#.&   ADKHB/<:(C8,6%"9<&=.77;+%& CGK'*/".#"7.&.'#/,,92)xv_zoLjS/o\EsP1cK6\F5DCA :"zkNvdJ}a>r_H_WMpeWzS9mO5<; 7 /2 :* ;)<): 8"&$ )"   %#)$- &% $                           M#pE *   sR+ie|)    %  !    ! &&81,$   !                 !   !)1%!4$3$=1$<+ ,$, +&' ''*"##')"&*"   *',%@8,2718AH ))+)16;(  DNJQK8H=+HE397,7G6'OIB'()!  #9?53/80!.@2$<9-9*..01(@D:}~_ibNxaFjfGZI0l]@VA#GEC%$ \E4oyY^[CiV8TG1hOC`HyM1N$@& A%E'D)?(* :&:,3 . :" + ) #   ) ;(#!  ' !                      "              &&       * $      ,"5 1&'      %     '          H8 i[L,%+    % t^3twv0 !          ! "-"        '%#         27#;/*)'-'61*'$" ( )$#%# '."(* %$!*('#  #$)*!%92&<>;! 8F\01,+9:6:?)01).,729zwec`FXTAQIBKH??9KOH_TATG/G=%E?)PC4U^YFC8$&!(8:'0/$47"27!%.2")05570 ""&35'C@.2- '#,'GB5fudGxWdm\+dN.H@5$  FC,s}c1<11*;& 0% "# )0"       !                                  "(! "  !;."+.$     ( .""&* !               ' " $!  ,$%    * )%##   `G!iv)  +            ( !                  *):3!=5&((#))&!'&" #*%63!!( " $')&*  $$&! *&"9($B:4:9@ "'&FMP&&'"!0ry@5.! % 5=6HA7JI@GI0OO2MA2RLDOTQ28<  (=DQ9;0"$)$'%$8/*05,71"RJ@yrawZBXG00B7   "*<>))#<0@2"+$)/!70!*506B8D83z\@nO;dG*bA"J?)F?!J:    |^ecG_Q7jXB`Dg?V_4B' A%?-<*C+A'7!;)0!8A17*!HA&,&0 %# '  * ' %. &" !! # )$$+*              %'    !!             1)#%( & (# 7,.(;$/+& ! * % ' "   &.  &           ! *5,-(/$ *% !)  # ( !       >1mUkCwKC(;!<(1 9(  mTxy~-!$#! !   *(% *     ' 2,%/0               ' ,#) ! '$!51#0+%?3*3- $06+*" ,!)( ###$!#"*-)   ! )$!+"!>,!+/!6BK10 !RXb-,' $, JHJID;G@'?6'=@.EA";8+*.%;,1,#B>2G<6vUxt`tjM|jGkK:V?.cV3^]SedWyY7^bB$L4E+D<&P5E'?'@$5'#>4*:-!A5,J0!::"+ *, 7  /2.% ( .5%5!/)-,:," ' # ('C+"( * $             (            & &!  ) '!.(#'+&! %&#%"    -&+0,%$%!$!1($!$!         8-)91#0:+&1-'(#4&!65.'1-!      E3uva\<:?1#8$/$- # cJ*^xF==   "  66$  $        -             !"          *&0.>0H3)[9'@6+&!0),0?=.E@./.0)0)/'!%"       7B<086 #XPXA;0 6=6HI/?,@>5@>0:5*HG3<=% (&   3CK'*!+ #1%*$<:'$%0<67+#xwbj`FviO]O;vuTzvdaN-I?&`V>mX@leTm]EqdF~l[G4jXDWF9wcGoGtfLV=L8E4R? E'E-:!J>'E=!$;#C#YA$K?);%8)B5;05$ ?!P>3 =7@.1&/*'#   ##%(              $           "       ""%        5>(+9/"*&   )&     ,$nt\xI3-51& !   ) vZ:gy1(2         .+   (7'   $!#      "  "      $ +"PG4mdSdS@("##'$#"/*58&,,&"$"$##  "(%! '-. " !$/94)/!13 "&*=\UR^XI ##.0"/.#><040 4:16@45@2 '     )$&$!'+8808+<2*=:5>1 "(0 kk\bX9NC/XC2oU~{jhbSucRsj_ifVxgL^WGQ>/qbvfPkjYfY@ghUuZzefM-X< C4$4!L8">,D8F9WMA@91.:*5'5' 1 )09* *&)" -$ ' !  '/4+ )"#                            "!              ..4.G!+4"# %!-#,,.!       ,.YSG) &#"    '!jM&GC?     ;$+  #    /$              ,#8.M>(x^PG)0(/8 .:%,*-'0,%($&+$,$!"$& &* "3,+!&!  %(!"  &1&'+*  *,1ZYT|q_  14*)(%%'7-$=<.2+/#0C*A,7*:6%;5+.$',*)'$ %*,/:*<=&*" "4#{_G\BjP;x`D|y^bO9q^?\G1dTCVK?mc?SH/TRBkfLocFG9$VE'mU=zbqmO0XGF@'8 T; G8G.G3JD,=3#!4- %;* %& ! "                            )    !  !!         5.+5=2+(%  %8'#20!##  ,%2(O2F62(, 0 (dT'y:,6  %       081?"            #& ?,F1-v^omUC0"44)#1"%$/*)*(%1'-$"")+(( " #"$!$'!?5$364  !     dYTsZg^]JNLS`S'3##'" ,!20&6.2++(#&%04,79+#+)'+)$ )!0.#,'#!1!+%$(-E1%xrXvgJuUIzs`l]Ri`JaH5ueH`YL^F!]I2dN9v\Dh^Q^K6_VRbZFfB}a]@(C1)$% &#9$+ !')#        "              !      " #     *& $'  # '&*"$      )mN0D( $' 7j_8|y]FF      * $:G,FS3,-                  2&JF6xvWj\B:-!:/*%*'-,,#&!"*$!75$2.-2)24,3./!(& $'   ** %2(!$%")%"%&$.1)'0#*3/-%2B?/0/$!(#"++)DA?TQK!$.!#!'-%! ))$'',+):%H;&: ;81>3).&0 . *!60!!% "! !    ! ##   $"                  !   ! $  "      ""%"      ,!$       $.1!)       !% & !/63")   #B."##1, +     (jR/pvRBD     (         !+@ )8"       !   ; JJE~vn~qmumgIG6""            $ +'"G1mn]A83(")'# !""#$,1&38&-@2/4&33-*1#*%&9% -)%&'$"  "+)'&/")  8:*+2&'+=8"D86-&<,;;,622SD:_D-6:--7)&%"++**!))5))35+,")*!111.5)5/(. 2025&)&*' )&&$"(%&,0<3*$.)9*/.(wxKQB96,LY=c\Dj`FH;%<,'QWGL>+8)#67%<0G8:.!2'A0#d`R|ydFgT@ F7"=4A8C@1H9'I0 ME/A;4,!6-=8 9 9&/!+ % .+    "    "                  ! %           )/!6"      "!           *(&&#$$&*/4,2(*')& !! :4ZN5   dg` %$%  '!`P|U@F          '9#)- %%$//%% !    '            }ı÷̱MRB%                 &(%,&3&'bK6kqLk}`EB=$#"(*$#-(&,!""43'2,)-,#$-:9:J@6-'!7. 58/$32.-$4)&""#& #+&(,( $!,(  #/13!'" %319!&,##",'#7=G6,%]XaBGF.'$"(% &     #!')$3"/.$"R2!o; Jo9 `- jKzsZc:%SjdEmV~uycGgV@xz~r~SA0D4&N1*E7)H8%A5)JB2B:6D@31&&-%9+'$%+, '.)  !$+" $                (:*        #&!%.+!   #          /($'#+(.-'*** #&$*"!*   U5!|le=pkH9<6(  #  ) X0bj}PFL       "   ,AQ1(  $$3   ) 9; " '     #1{īʺѻӶջӣsql=%s{lRG*#    &"! & jL"z]@A    *C&@F("       #3/;JixyƚӸ֨_f_>PT  '3$A=8$&          "  % # &( %WU>svcmi:/&=<:%"$*++/2QXTMM@Zfj^`PMND:AAL?-<.*.-!70(,.'+&.,,<.86-17'")+&# ! +,''4 "*"+6(73.=;)C;5;1*=:,;;0>83-9.J?4gP48*'!&!#%+&&-.-,'!$ % # '%2&#))':=+7.=96%"!('#!81/.+$81"C85xpa{kcPoc|gPm]KpX@od_K?yh[{jtdO~qcSI8L?/I7&G5,zygMpiPH?'C2=/;*D;".!.$:8.>:+6:0&1%+#(*  !$   ')3A2*-"'! ./-+    +%)        #      #        $$(0*;0"*' $                    2)**&)%41-)"++& ##&&".*/--3%$&)  -cYIx~fOC *& "  &$   % gA#~m\Ta                   ($+"--"      )   :%4,"./(7/'1-(+3''3"!')-!6'!)  "*&%A40;177!09-9>;;61@BB9:,+!  &"$%( !!(#,)##**&-"(*"'(&00-..!2/- !)"/',-6)!7<.eQ;kXG~qxp[yneBe]=c\QEdte~ra{v`j_Fjk[LL5^dQD=#aia~zm}mFfOCI0:@F41ɂHWJ^z1F^ 4    7  8?     !         "!/8/A?2jbV{JH5 "'# #A<1@>A50'4**($ !"%+# # +,1%'+-*:6%=-+-/.*'%8BG/.%B9&umVE=<( #"(()#"#%!"$"% !)& $*' &""$7+1$$#"#7$!aeLug__ZIumTncOv|l?:1iqmGD4\L@sQ{mWjYAB@5>.%A1"@2&PGBslbngXaVD@4''#"'5.#$(/ 2*&E?6482$$!.-" ='">)"C <;7'DB/J/+7 :9H*(ksQE:A1)+!7P9/7"   (2#7 1" [>9mexF48) 0'#% 2 +)#   %         % %8.";:*#)(          #,    $ &     ('%' 9&bD,.  ' `M1NFB         #-%$lU(TF.d_[]TBIF2G7&1* ''!#$#*$0(&3)%cH7iim'+ )9,Tii`lY_h`[d_9:$78&{w^KI( E@*T\W0&#C8'FF=\d\KSGA9/;3+M:-¤ĦoggZNJ@85(d_MXC.q^ml(@Y--AXWEO:\ht̾ؼָͭ}   - '                 +16,:LXoOqBXjbvDh}$#m}}LYX$/&    $#       !!   %*&M[_zvejs`7(  '((+#&# &!%!  $!"&     !%)' #  !#&)&1  "#xezbA7-   "&!'(+% !#"-(&* $!  $(!)# "&+-atyRe`801]YOo_I{xlefaB>*BC3]^H\TI^^P&! *-+LD6PK=bdTC5$@=11,(/& .("+&!/429/)<;$C7 w\I"  ). !$".,77%bidɴҵϮΚŅupD75-!:10<&%'4! 6!u_;ѵղֳԷ׵ԱТqPfsNXg~O;88",!1:(                %!*     !" /'(?;';>3+50 (    &'      #                !   )  "_O9y[XV/-3-!8/!hbNxazl_m]Tm̵ȼԻ׶Θ/Fc.:-LdjԿ׾ؾںٻ׹ά̆',B/#!83A                     !         %           3P!,#k">M?N]{nuäřÙ{EdeJ\x0& =CD><(       "H< E?*"        %    -&#E#jCi`Bec7:8%*2@'B,6%.*%,- 0->4(-!##"#"ZLDk[FdXH,()! $!,DG%- 4+<"@( $ $!!,#%#9-6&")/&|}g~jt`Cj:2"$pytoz&%&  3M! !!#B9"9;+ *    #+%+,1()&! ! O[WDMHDP[VTH(:602(FLC;14KE;(:.#! &;2"@7)89*6;,,+''! ,#-)#9;/@A05%#h`Wjg\!' )2   ")#+79KDӵضַ֫ÚueVQ5"L8tVxWmKѰ׮Ա֯հӱҭԨ̛sYZmUƂkYNqwwm          *      !*$-+ <1*B<'<91# '$ "  )',*'      &!  "&(      ! $ !"(*#.&&-!6-!,'!     - M100;F0 !    "Q<voxdKHC_H+w^>a˻ҶϳƻлӽֿؽټֲֻdPPA8%H3"oXE׿ٿٿرˍS\dv~~[ivgE(d;OG5        *;.!E                     +       $A% 7Je;ESXjnǤˬ̤;KH6CQ@X^7BLLx"        %  (fgZ{z78, !xY:9# pE4KI;,'(*xV~hU<((-oxmH$."%#sild@HB4~ugȺ˸_iX'!('#V3K%u[RTaS*"!-43$""Ш<<;+-1-%/7**5*2& iKNzV" "  ":A?JB3?A6}{W^W26'76259 ph~u&( !<;*  #$!)& 3,"=C6'-/!!*!&&)'*#! ;1  )Y-Y2g= cO; W;dN3fN/kM*-.  E;(l{~\xuc'.(,%#.+$$ ".%!04.8.%-,$85)/a;'LG<7@C  %+*'1%&1/:,tӹضرֶ֪Ρįή̵ѳʹ̰ѸֵӶ״կӪҪԥӨѤ̣Ѣ΢Ϧʦ̪Ҥ͢ʚƗƖd             "5,#<5*:8!'+'    !   %!"!'#             $   #+0*4>*    ?6!ADB   LA2     O0hy¨žѼӻٴ׻ֺٻ׺ٿھ־ػطאôĽ׻ؾؿڽٿܾܽٷҘ̡X7*=*5%      !        )"$ ,&Ba  #6   !   " 6 +&    +     DH[!5Mj4:C<10>:5ټٹaa\(" 7 Ѷfgc1 (:'%֭C2*",!GKG*+" SB?}  >]K>  f][A;,?>/:"|n]XRMvPpRzcBBD(=KRvj_B_[LfU@a_<"CUKS_^LXWV`U.2$3&A:(W]QW_UPTMGTC BB:IQDNXBC^Q, RS<]Q0l]:B?.  79&?E2ED2,88 8,#!  1$& $$.#4*5:(:+!/"mUHbB'1& )#!"#6"6<KF-,( I:!ոٺ׺ײرӱ˷־پڻغ׽ھ۹ֶ׶ӳ֭ժΥѠ͡ˠˣ̦ͪ͡Χˣ͝˖Ɏǒō`|             :,%0(&          % 6*$28%#/   " SAqum˸ϺѻлӻӹյշѹӸѼӷշҸӹս׺ָѷӹϷѼսؾ׿տ׻ԷѮƮıɳȼɽӺѻεǨr_Sv^TYcb,"$       A<$@    %7$2'!2 .  C^vMQ= , 5!7,   $   EDyկӕo3+FUXUf! =<4D/!YYNkP9K:!4:;HE/HOHHH@SJ6˶غ۽۽׼ۿݿ߾ݽڷ۴گ׫ԢϠΝʠ̞͝ɘ͠ɡ˚̛˒ǒǓƖj        "          Y%M%xBoJ#0%#  &  +  A>βӴик϶ԳԵӱӷչӶҵյնѶԴҵֶԵֹ׺ؼտӾؼ׾׽ھֽۼ־ԿؽѻлҶɮǛ[D>/        #*+-. ' -F6V  )"('    %,9   "             &$( !2X&@^$ NdovM`L϶շثϤZnx&&0+;PHh& '    ! + DP+YQFu#( %  #%!B5-4'C,CC:=<4K;+{XB˻ڻλμؾ޹ٻԽӾܾھֻּؼݾݾٽ׸׺ػټܾܺ׼ؽָқ@3%:61D>6rudLep$&4%%'9-2;16);%'#3,%KG;`WA~`Jˎ&.@ .3 ,@53?BWu~ro,')^^C    *++  5I(a;J, 3-?it  !AE$#%!C7!=A0W]R``AVb^'0-&%+;;?&+/258)5(5'mN<Ȯ\b@/' (/ J;&Խ߼۹۱تخذՠѠ̟ˡ͜ɖǗ˙̛Ε˙˘ȕŒƊx       '"              %'$ %(".8=AA606859984 %%!            ,#,)#      $"wvWza\)   '%   A2˪ΰϰѮγϭѮԮ̫Ѫ˨Ϭ˭̱ͬͪϩϩ͵ҺҺԻֿؿֽ־ؿˬ~YHwN2                   ( 3   &,d{kwl;3(T`Rus;.2.+/          @Qd) 27=8'%ҶӳӤФ`SK18:+'-   GOAbhWTYE*'0 % %'*5%('#B8%LD-?+ed_rjȻֻ۽ݻھݻܻܾݾ޾ݾ޽޿ݽܼܼܼܼݾݾܾܽۻݼۺۼܽݻܮ\]P;=1cVPemW=;RE%0!-.'!02:XH":% #WK?k@Y^+:/#J5{n%10   ! "  8 M9L0@2$ 1D=,0  (!=6"2)40&9:,-*#($!/7=HBKWJI>4/*2)-#w[Eÿ((!!- :9*;?4cO5ۿ޺ڵګժҨզҘͣ͢ɝ̚˝ȗ˗˓ʛ̗̚əʗɒx                      ??$NL4;94 '&!!#/-    &+      !###6? #      NE,ZA%eaKTI<! !   "L?tdƧ̤ȟǤȧ̦ɣˤƤɞȢ̩ʥɦ˩˪ά̬ʯаΰѶζԸֹһѶҹԺػ׾ؿڽֽҳǜ'     61?  #!!( JO@   ¾ PfȘȘu!&#"   9Kha[jr    (    2$,%#J[i̛ɩҫьw~:2,I;7,%(4ES'72        %   ! &%" -*E0 PPbCMIJckiphɹݽ޾ݻ޾ݾ߽߿޿ݼݼ޼޽ݽ޽޾ݾݽݸݽ޻ܺc_d2$_WOI@*5/1Sgp3>-*.F\QD=%8C<*6(*-& >*&lzBC9y\]T9<5CPEyĞgyewZq7A=$'# !&&-  $0=G2%9-    ("F9%0$ ($"2,,90" 95=GHUINS*"$AA@=22fI.ÿw_L;;%.;-KA,2-"QC-}]޸۬դңΤӢΪТ͜ΠТϟ̛̝ˡ͛˔ɘʑəx "     #               @.|_H9+!                        !!        %!!-& 1'#50$:1)  ) O0{qƛƠƝĜşĠŝĢɡŠǥɨȧʦ˨̧Ψ̭̯ͮϯѱе͹ҴԵҳӺҸӵַ׺ػּ־׾پ־ռ׽۾ۿץxcxC1,EHUC4=QW_jhw   6;@+&       "'  4_S=" *G    eɡʜƖȡǤˤŌ}*>>  #OlTxOk&!- )@M          "# ! /3  $/1Se]nĢPNJ7OI=|Ω•ʪѐ̣Ü6>7 ', !* 2>%+4$         )#+?6+,  ")"$-6*!JB2;/#$)..*,!9<4HMMJW[UNO.)!,3#,'#Q<$Ƙg_JZN6pdPvܲبӪѥЧТЧϥѧӢͣϛЖ̝̗̕ʗ˚ȏ|#  25)   5.&:2+            E:#}l\75#                          +=2&-%%     L;$~mÛ×ƝǚƠɞƞƜȡɥ˥ɢƥʨ˥˧ͪέˬά̯έ̲ͯ͵̬ήЪѲԮѬϱ̳ѵҸкԹصӶշԺӶԹջؿӻٽٿػ۹ֹ̝֫͒1-Q       Wkn̦θ۩ǵٶմդ͢ΨҬդȉgj[ !"%$ ':,      %!"    9:*6>" */-+-%VZI55+"#0(!*#/2,"bYWyQMP. "9)=3,Y9)ûؽڽ޿ݻ޿ݼ߽޼޼߻ܳׯ֮תԩҧӥҦӧФϦҡљљ͘Θ̕ʛ͔y  K@<  C>5 LDB#G4"9(%         $ >&ye^S                           -%?#'    U9!jęĜƝĝäţȚǛʢˣƤǦɤɧ˩̬˯̮ɮɪ̭ΰ̲ѱЬ̭Э̨ͪͫΫͪϧϯϮ˳γѬά̫ѪѭͫӱүѴԱӱӰղױѱѩΨ˦ɰ˱ӱԯ͒"     FL6\n      "  /8A34B     4!OGp!!5  wrh"&= &¾ " @[oAXx%6<)9WRhowvqpŠƦʦɎ@<1%1CL`L_p% $0 ))IO@E=?(6J$$      % #   .6BSip\jWvPXB#;3"]`j4&"B:0[]_5>8"         ''"   5$(&!>0]jqxtkg޽޽ܼܾܽݿ޽߼߽ܿ޽޾߼޾޾߿߽ݽܽݾݾ޼޵Ҥܻ۽۴تÞfsYj`LĻزվ۷νٿݻܦɮǛ—o06$(%#,2#,"*6$  1;*) '()/:(,8),   $*#/&+-08KJ-=;)VD0@7&70#A=2166*)!!0DR_wNnDR\+&!0+(-$`D7Ӿ۽ܽ߿޽޾޾ܼݽ޷ںܶٶصճֱӯѧУѧԨҤҠТ̢ћϡ̘͗˛ɘjlt"+mti  TJ: 'r^># PM=86. *i[M/$% )   ! #!B=$w5" &         !  $2)   #%+  %          & C0+ % '   C*| ƜŠƤƤŞǢǨǠˠʥʫ˨ȨΪά˭ɭΫ̮̫ͮΪ̪ͪ˦˨̣ʡȤ˨ɦ˨ɥ˦ɨѩɤ̣ƠǛɠʡɢȤɤšǢʥɦȥ̦ˠɢɟœħʪ˨ЩΧɔ3#"   ?AEVdwki.!!JB3?HP!!#     '4"c]JFTZ"%&31#./5!3,,#""5@I:!-(> Lrt4 ID%Go 4 ,KBY_#$¾ 8:Y|#LibQaguh}uwiɨ˟^y}!$.)(%; &)B       !        "84p@B8#""KHEytƘ>[~A[mgswm|C]j$?G2?  5-           +1$*'9)=9+FGK=8;@74TYiƶػ޺߻޻޺߽޸߾ݻ߼޿߼޼޼޹޼ߺݺ߾߽ܻܶ۾޻ݻ޻޹ܯԣײ֗EK@ɵԻݾ޻߻޻ݽ޽ܼشұ֣ĥz=FL/IN"3),,) +(+>,!-' %$-& $ &(&5*$'!%&$&  .)(;*  WPN#'3 !  "1+SB)y}\PD   ?/.532 &,+  &           a_O,  G:(;>/   5*6<;H6%pĚǝğƤǢƤƤ̤ɞǫΦ˥̨Ωʨʨ˧˥ˤ̦Χ͠ʟɚǖƕǛǘęɔŝțɝǙƗȜȖĝƚěƔő×ďØțŠȝǛǜǚƛà›ǛƢȡʝƒpyOLI2>? HH=06D  #!#izqr>HS510%      &# $&381?KW=A;Tu>Tb8Rj* 7P_ .QFT *' HG@02D,;I  .$+/63b      '"/û 5AX9DT  !1! +& 00/88+5:*,=7_nɢ826    $8>         &CϓO`oSaYblwe}Sgv) 0'(Miz   -+/     7CC    #,  )!&.&.* LTb-&"9)WMA|Ѻ۸ۺۻݽݼ޿޼޿߽߽޾ݼ޽޻ݽ޻ݺ߿߼޾ܽ޻ۼ۽߸ݻ߼ݽ޻ܽܶ؛սۼ޾ݽ޾ܼܽ޽߾߾ۿܷ٭ίԥp08,+-0,J?1OC-9E-   # ,#:7 8.)/!>;?= DF..BC-7@@D=4cN;@<IH,JK2XW1_fPfc]`\T/(!-'52(82'# # *#"%%'((#21#@7.pO5ܽ߿ݾݻٶٳװױֱױֱӨҧңΞѠѢϜΝМϢ̣ɠΟ˘y_cUWI9xqseM8$%`L7E- +uh\0/6  VLA# #$1:>1 bZ:hO=  !             ,qrS@e:!W3 %4. B;3#  441"E%hrnƥȞɡǣǤȣɪͪ˩ɫ̧̪ΟʤʢϠ̤ȥȝƝǝǛśęė—”Ô™Ĝ×ǘÖØÕƖßǙĝŒŝÝÜǟġȣĔE@KdZUw,/C# !"23JLNQUZ@=N,<    @D>C?#\djHBY6imYvIPY&  00TRs@0)..N>QW$-Y  "   +# 7 'ü!_\@N[h_jG '3  '3^GoL]BihMtiH̨̪ˑ\lm       %*%?L/ & #    Vcgƪm>=M=NqWbnef]_NA'30"($).CS$&&G.\kurnh]ZF0*!        "$*& ! , (%D1B0LGB_aM̺ڼۺڼ޼ݹ޻޽ݼ߾޼ܼ߼޽߽޿޻߼߿޻߻޼߾߽߻޹۽߿ܻ۶ۺ۹ۺ޾߽޽ݻ߽ݼ߽ܿݻݿݾߺޯҶأtOYCAP3+$N?>ѷۻۻݻݽݽݽܾݾ߿߼߼޻޼߻߼޾߻߼޻߸޽ܺ߻޺޻޽޽ݽ߼ٳذպܡ}yjX0+#00()2-*,#++48'+ yi>6( *Oju[is>:@dlsFB;PXHhzQUJ2-%;9ARebebUսڿ۽ػۻfbc/%00)0.+)//"!# $%! $ - !5&"y޼ݹݵ޵ܶ޺߻۴ز׬״رڭԤեҧӤҨӨӨӧӨӧѨѥѪѩӫԱұɲͯвα̯ɶϨlZ_L{cZC)(,     * L%=*&B* @4&B)B,@ ?#:2$! * , / "( ?' (oOTW+%  ($ĿHP|:Rk-Jz&"    2FEbu˩̩˪̰Π}xj09, !     '"( &"   %)!RmvQhįδض֯ьtlc̮̙}~>FO>LR?0,?3#!        ,""%2/A9!KG2G@+:?+PMBD8v̻پ۹ܼݻ߼޾ۼ߽߻޽޽޽߻޽޽ݽݽݿݽݽ߿޽߾ݽݾ޹޽޻߾߻޻޻۹޼߻޿޿޽߿ܹԼؾۼؼ׷ГJE/64. I\aIB4d[Kՠ8D:05+RZIlxLW_Ws{XekTcZ@@2==5\bpME=og\i]Zлݼݼڻܹܺٙ4+'61/!  6)!C8+ZZHWYF_[JqmZ^hcnwiptdŽ޼ݾݾ߻߻߽߽߾޹ܸݴܸݺ޼ݵ۲ص۶ګѥӣԦפԨϨ֦ԩҪӦӤӦԯժҮԱֳҮѱѳֵյոպֶϹֵӵвŰN=:!$&6::161:1)2*1WK7\;)+" $ $',&91%,3+# !''&+2, #"%$   3)!D:.*%#""*%)=@ #&'1/  %"%-8 #- *)#'  MF6`\HihVjdQ8)<*<9''% $   $$**!$0([>ǨɤɬʩɨΧѩФ̚ə™ē˜•—ŎčњÏÙŘřÙǚǚǒĘƗۛۛšŘƗ׊ĤĢŢġgfo?'6-/8#%'&$#@55LMHv˱ʲ˵ϴ͸һӼտԾ۲ѭ˴Ǣ~WPA     +:(Et - //ýɋqu&/ )&%..+(.**DIN`B@G@;5CL=/3(( "33+.-! $!>696";3 >9+VP:ek]weddx}vhغۿ޻ݾ޾޽ݿ޻߽߿߽޼߽޼ڱș}j{ԹֶېV\OhjGqnsnukZ]`nskpwpl}}Ӻ۷ݻݽ޼ݞ95.5/14<1#+#$!!'+(76/4,"$0)(G/)Ӽ߻߻޼ߺ߹޶۵۰خ׮֭ԩثר֦ԨӫӨծԪְخծѲֱֱױ׷ظػظڼۻۼڼܿ۽sor'&0.-53#++$*3SA2T@2% #.-"-916-*!         &==B5)&                %  B7I<--!/#7/)"   '55*>4('.*=7F1cZ9αӶѴշ֡̉œƛªƔӲѤĜӶӱΠ{yxOSK"#$ %.3'JE=B@1/=?'-+%."%>4PH)UL=HKCJZh:(O@:$=,(xNeHXA4) (,--6'$# 2)-J*$j<_//)%H8$tF!m=+'    "cI0]4,?   !1#"$     2$X@/C9$    "'       ( 0%.91+6$&"!h`Ḅ˥˩Ϊ˫ЪѩЭ͞˖˜ǑėǔƐ萌”ГØÓĐƒœĒƏŒÔ—ÜšœşśŜǠʦǜ¤ãƣɦɤ˩˩ʤDžvkdmfhɱ̰δʹӶҶԵַ׼ؿܹ԰ĺήÞ56XFGg4"%9<2&59:1,  #4  o6'*1=8Ľ_`Z=Jx!/6"%,"3KJ">5 '*67PD+ϱҮб֫ԫΪάˤʟɉdlr525JTbN]Z;BD   #$"00'& ;BF)>,      4$]P2eIUHJ,#   lg`&#%   qmR[j}   C<40+  -&',6))F:/dUD̩̪άΨ˭ΪѤѧѤ̟ƞĚɛ×ƙƒĖƘŕ–ƘÌƓƗŚőŖƋ׎ÜƕÖלÜƚȝǜ–œƞũǥǧŦɧˤ˦ɫɬɫɮ˯ͭɱ̮̯ƫɮȳƵ͸δѶԳ׺ӸչջԼֽ׾ֿٯǍĐ]JHLjrypxTTDKjBD<666 )  ]ONdgwIWUſ˥naH@>,0,#98#HP3W^96?)KU?[gMgjHγΪͮѰլЮөЪҤ̣ǠĄmyzYix)-D#+     0,! '"& 1=6,%$   '0>2pq\̵ѵҺҶ׹׺նͣiFoX>si`sؾظڻش˂ei~{R^TPTIG?1D='>8'" -"X[G[^T0.92$FOJ75$@6'VLGncV{gXи׻۶۵ܷ۶۴ܴ۶۶ٷںۺݼ߻߻߼߻޸߻߹ߺ߾޹޻ܾ޻޽߻ܺ޷ܺܳݴܹ޺޹޺ݽݻܻ߻߻߹޷ݚ672-)%$$5/.OJC3*"*+#'(10/>FH% )&%:+#yٸ޽߻޻߸ݶݶݶݹ޺޷ݹ۹ݶٱررٳس״۽ۻ׺ضڷܷܽ޾ߵ.   " N+`9o@ S*x_)!dF9ӿӊ5,$(&!+()#:9/\HE !wԵSII  $ӾZLK! &̢9-*   ȝ-+,    wy}0&2*$  %".'VG?ʦ˦Ϋ̪ͮШΨ͢˘ŗƙş͜ŕוŔƘƚŗÔÙƕƏĒĒÑÒÖٖØÚǟɚØĝŸâǠɦȩƥƤǩ̪ͩɩ̱ϰͱҰήͲ̲γбѴεѴδԷӻμӹӳѻ׷ոջֹֺԼܺխƭʐ\g!!+<FNW+.@Nii#9$( #EFEv=Jehh_ƿ̹аȯġrɧƞŬʰάҪΫԩάԶճ֮ЬҩХΤ̡З•ăWTR970(              $##'/BI7;0DHQpM`l+3&    ,*B,01+9J<2>/͵ѱѴӵ׻ٺܹջ׷ֻӽѵ̱ܾؽؽۼۺۺطѩ{~[`cMGJZL5FD,QGB}l|{LF/B<(XI4q`A~lŰв׵۳ح۲۰ر٭׮رخخ۴ݻ޹ݼܹ߿ܻ߻ݹ޺ߺ߼߼ݻ߻߻ߺ޺ߺ߽߽߽޺ݵ޷޵ݶ޷۵ݴ߳޷߼޺ߺ}(&+,#3+(~xsPMF"%'*&"ZDDD@<%!$60'xr޸޽߼߹ݴ߼۷۲۱ٰزٱڮظ۷ںݵݹ۸ܿܿݿ߼0+3##((*&B?#yU;&}`ܙN82I2*L4&\?*a\I~܎lo_:(P4&R5"kY>w`Fջ}diG/$H-"E-D.M1#ymnG2)D6297*F5$U:'ղ^MPB*2% :(/'"F(#˥REE+<>(A+;$Tb       R@3 )(#("/-@:,ȨΣˤˤѢΤΥˣ˞˙əƘǙȕƗƗØĖėśȓėǖŔÙƙǛƖƕʍĖŘčÒŜƕƖÑřǐٕ›Û×ƙțƟŝɡĥɦ̬ͨίѯϯίϱ͵ӲӷӴֲԷηԸԷѻѸֹԹ׻ֽѹظ׺չҹ׻ټڻֽ׿ھۿݿڿٻجхc``/1R &!,"!!   #$#2Fb --#0#:5=`xwſͶӳӱѳӭαϭϬάα԰ϱ̮ӲϮΫήѮѮϫѧͦɤΣ˞ˠʝȞƖl|B8*1$!::=51  !           !%#  "-;;9/7#RI3SMFMYiYg{<;.?HK     2+-+"voZvfDhɷӹӺӹһֻֻعۺҿؽؿݽػ׽ٷٻؽڼڱѪ̡™ɫ{uzĭѵֶӳذزֶۯֱزٶڰׯְֳض۶ݻ޿ݽۿ޻߼޷ܷݹ޾޼ܾ߼޽ݽߺ߸ߵߺܼ޽߼޻ݻ߶ߺߺ޼߼߻ߺ߾ݽ޻޾߽ݻܸ߹߶߻ݼ޻޶ݹݹݺ޻޻߼ܺ߹ܛ).0)'(/+'r^VJ/%E2+WTUG'!R4%ɷչ޺߾߽߸ߺߺ߸߸ߺ߽޼޽۶۶ذسذմسڸ׷ۺܾݽA43 '# 5B8,eټͿҴwYüп׸ҕǸ´ö˽նЫrIXXv      1198. 1 ?=<^QB+'(-"$($'B0!zurªͪʫΧ˥ϣ̛̟ɜǟǝǛƙĘŜǛƜɛȖȡ›ŠǝŜŜĠ›Ŕ–ÕƘŘǝßŗǐÖĔÍƜÖÙØĘ×ė¡ĘŒřƞŜƧ ĢǣˣȩɫɭȬ̱˱дѱвո϶ӺӸиӸѻռٻϼԼѽټؼ־׺ֹֹԺҶԻһغַؿٽ׻ո׺ػԼָֺٮɩćnnwibXHDGC>B      sa3^pu̻׳ϮҭԭӯխլѭձӲӱԮ֭ӪӪӪѩѤϢ̙ˎ̕ƗƑ‰đƉtkZTZ`X`Xet'),+..60)695**'  .*  ' +"( #%'" *$XUhyG]]7IH#@c#$   &4(73"ʸұʳкռָ׹ֹԸؽٻܻھڼܽۼ۽ػۺݽۺۻ۸ٽ۷ڻٷɟÔy|faλֶжѲӲԭҲַشװظ׺ۺܺܶ۱ۯذڱخݶڴز۱۰ݷ޺ܽ޻ߺ޺ݴܷܵݸݾ߼޻ߺ޷޸߼߸޻޺޽ݺ޺ܻߺ޻޻Џtze|oٟĸ٘Իܹߺ߽޸ܵڱٳض۳۵ڶݻݽ߿C89!;4'KB+w{۽ؼӶ^gz     rUtzvl[OA76(#%*(###"&!$$@6$z̦ΤЧѤѤʟ˜˙Ǚˡ˚ǛʡǟƢǣȟȥɢɣǢɢɚɠȠǚɜǞʚ˛Ɣ֟ÝĝɘŘÛƕƖÕǚŝŢÞěÜĚŝǛǞƝƛǠǠȜƠǜɠˡʣɦ˦˫˭ˮ̯ίбѳеչ׻ֺֹֻֽغ׵ԹٿۻپؿֿۺضٺػعسֵԲնյյӹϸճԳҺӵ׷ӰԚumnO[yuf[y?Gl=8B02FF;2(7I$   (    ,96" (&& 7eҋSgn͸յծ׭رׯ֪ӦӤѩ֪ΪӪΥџ͘ǏƑŋ‰nPA2TA)OA*?0'bGTtbmpBGDMKI82% +$ '()).#&3"=/%VKMPOZ.*'! & %! %'%ҷҵӶԶӸնոֺֹԻֶؽۼ۽ݺںػۻӻعۻ۸ܶػٻӻٶٳ׸دѢӼٽٷغضز״ص۶ڳٷطٷڵڷ۵۴۳ر۵ںٻݻٶݱٲڴٸڶٶ۲۵ܴܵسس۹ۻ߽޽߷߸ߺ߹ߴ߶߷޸ݺ޷߶ݸߵܺ߷ݺ޺޼߸߸ߺ߷޶ߴܺ߹߸ݶ޷߶޷ݹ߻ݷ߹߹޹ݺ߷׶ֵֹظۺٽںݺݺ۹ڴض޺߷޾޽޴޸޾ߺ߻ݸ۴ܰխذֳطغ׸ؿݿ=;?;>=50$avڸsz   #*#!"}munpȩɏ@@6,&*+%& %?,uǡȢˤʢȥ͞ɚʠ˜Ȧ˦˦ˤ̥ȥͥɠɤʣʤʧʧʢ˞ǟɧǣʣɝǡȤɠ˟Ơ˜àÜȢɜƚßǛǚƠȟǝǚǜǝǞ—ɞɞǛȞȠɛơƢǡǡɣ˧˩ͩɭͨͪͭ˲εҶַֻйӸֻֿھٿٽٻ׼ּؽؿ۽ּ׻ּӻѸҵԶӱҲѳѲӵԲӴӴѵҴҰӰбҰ̪kptHJ5HD>C5(*YTShbN\\Gll{ĤǢȨȤi  4<;NC%6("dceȭ̮ϪϪͭάѫέЮҮЫЬѮϰͫͪѮʮ˰ЪѴѴӱϯԱӲγԲӶֲβҸҳֵӶѴйԷֹֺնؼؽ׷غֶ׹ٺ׷ڼۺؽؼ۽ܽٿܼܽ۽ػٽ۽ؽܻٷݺݻ۶ٶڸٷݴڱ۷ݴߵٶٲڴݶݵ߻߸߶ܷݵݸ޲޸ߴ߶߶ݴ۵ݴ޳ޱ۸ߴ޶޵޷ݺ޺޸۷ܴ޶߱ݴߺ߳߶޵߹޹߸߶߶ܹܶ޶޷޺޷ٸ߷޴޷޻ݹݶ߸޶ݶ޽޶ݷߵڶ޶۵ݶܻߺ߿ݻ޷޼޶ݽ޵޸߶ݷݶܺ߻ݺ߻߶߹߸߸ݻ޹޶ڰٱ׸ٵܻݹO=<'"*%*70,uKrՊ    "}jrV{Z>302! h?`(m1s={XƤƝɢǣȤ˥ɤͪͨʧˬ̨ΪϨʪШϫϭ̪̪ЭϫͪѪϨΨʪ̪ˬɫ˧ϥ̪˨ɤ˦ǧʧǣȤǟǞǞˠǛɡɟəɛɜɡɠÝɥɢɡƣơǣʡȧ̧˨ʩ̤ͩʬ̭ѭҰѷѷϵдѹѻ׽ؽڿּֽԺԸҵѴжҲҳеϰϱβүϱѶҳҵӱбΰ˜ber\lt>GU00/ioi"*  #  $-$&88+u|mKFA-.,hrwzNdlή֮ըΤ˛ͤїȍ…ŊƁƊ{~zĔŕ‘“ĔȒɗŗǡɢȣȦˣˣǛyyrmYbbEvcaL{~ƤȢ̣ɛ˦ɤƚqpWhfH& =9*^ddʦϩ̩ͪʪΪ΢ϦͫϫΪΨά̪ΫЪέѫЭϬЮͮϲֲӱбԵӳֶбմַֹԹֹӻֻնعԻ׻ռջؽٺۻػټعؼ׽۽۽ݿݻ۷ۻݸݻضٷںܹضڲڵܸشܶ޵ݳس޶ܸ߷߲߸ܶ޴ݴ޵޷߱߷޵޶߷߸ݱܷ߶߶޷޺޷޸߸߷ݹߺ޸޻߷߷߶߶߷ݺ߶޵ߵߺ߸߼޽߽ܹڶڶ۲۳ݾJDE!$nK,1()-( tM>:[D;yۗ)!C4" <'D/$ uzzkb]˟AG_0-,&)$.%0,%=+%ɦɥ˨ʦɧɦ̤ʦ˪ˬѪӬ̮ʯͬͭЯѫԬҬҰѮѫ̮ϭϬѬѭήЮ˩ɩΧ˪ѩ̥ʠˤʥˡɥɢ̟̤ɟɦˡʢɠˣƢ˧ˣɦɥǥʧʡȣ˦ɤɬͬή̫̲ͮ˱ϰҲҶҵӻӻҽֽؿ۾ڻػۼԼԸҺղб״ԲҶԶӲввбӱҵӱӴծːP?GGAJ5?TCGBP\Kcuo{AJl'B62+  719    -$B=4;%OF*^cLQfFGW4@XGVn4?IStL^iɿͦΨϤМ͟͝ӟ̌LJƉxÃĊw|~}t…sďĘœǒŎ™ƕØȝȝǚˡ͢ʦʞʠģǞɔÙǙƖǓɐɛÜǚȝƞƖƛÞƙŚozwŢʟɣˣˣ˥̩ЪͤΤ̤̪̤ͧͧ͡ΪϬϫάӪΪЪ˪ѬѰҰаѵԵӲѶ׻ڶ׶ٷ۳ظֺؼٸػٿڿھ׺ٽػݾܾܿ޽޹ݻݱݵܶܶݶ۷ݱݮرسۮ۬ۮۮݮݴ޳߷ްݲߵܱޱ޳ݱޮ޴ܵߴ޴߸޸޹߶߶޴ߴݶ޴߶ߴ޴޹ޱ޴ݶߵݴ߶ݳݵ߲޵߽߱޵ݷߴ޶߸޸߹߰߸޽޻߶޽N=D2"@4.+#wsdL:(XL4}mݽیED< sf]gp XNDmi`^5,ĠʚCBV'"*+%eɠ̠˦̬Ϊ˨ΨϪ̥̬ѪӮѭҰүЭϨҭѮϬүүѭҭΪ̧ˬӮӬѫϯծͪϫФˤ˧ɟˣɦʩΦ˟ˠɡƠ̢Υ˝ˣˣ˟ǟợ˧̠̤ͪʢ̤̩ͪ˩ϨϭӰΰаѲѳӰֳճֶ׽ھۻ۾۽ۿܿھ۽ܺټعֶرѵбֲ԰бյбЯ̳ӲײرѯвЮˏUMaS@0jpRJb]hyX_xDMSM`WKCGCDbPEGCR54,% !   ML>numq/:Z<") %4 IV_ǾͤϮԩΧ̙̙̒͡ɑǔƋNJy~}ÅăņÎđŒďȏƕɚŗŚƞǡƟˤ˥ʣʟˣɟɞɠəƜȖƠǢŚǞƞßƠɤƝġğƢģǣˤɢǣŤɥɤʥˡʤʧɤʩɧʤ̨̫ͣͮέΪ̮̬ϮϬѭϬӰԱϰѯӳӱӷӹѶӹԺٽ۾ؽݻٻٽܽ۽ڼٿݾ޽޹޷ݵسعڶ۶ܴ۱ܲٵٱٯدٯ۰ݱ޳ݵܵ۲۰ۯڴݰݰ޷ݶ޶ݸܯܶ޵޶ܻ߸߹߶ݹ޷߶޶߶߷߸߷߷ߴ޵޴ܶߵ߸޶޴޶޸߸ߴޱܶ޵޵޷ݷݸ߷޷߶޵޶޵޵߶ܷݾ޶޶ܱ߶ߴ۷޸߶ߺ߽޶޶޹޶߿ޙy_dNB4<i?+t\F>%}W0oT1nE(y˿޾޽߿߿ݾۆu-SH?  #jtM97`UEL,!yZ.ȟśD?T*'%-)16$7!fw~˧Τɪ͢˫ͭϭϮѯѲδҰұҰѱմӴӰϳӴѳկЬӲӴӳӴѴӯҰӯҪͮѫѬ̧ˮ̤ͤȦ˥ʧ˨Φͭɥɢˤɢ̛ǦɥͣƧɣʩʩɩ˦ǩʪΫʰ̭ίѯЬѰհҲжԸѸлҲԹܿڼٽ׻ԽַֹղӳгҳճѺҸѷӷԲѱֶճϯÞCC_WOfBE87@KJ>9Q\~RTK&3B//4* ybg^PdWCyQոԉYFd=6E1.;2+ Ufq8?TYϠѨ׬ԧը֤ҖΎǓɑɖʖ̕ȍÈÇÉˋČȑŌǓǖƘƙǘƞȠʚʝ˝ʡͣʢɝʣɜɤɤʧȣǡȡƘǜɞǡ̡ǣǢʝ˝țȡʢ̦ȠƥΣȢȥɣˤͦˡǤ̪̫ɥˤάϮүѲѮέ̮ЮӱϫϭҬӱӰӳѰѰӶӶֲ׵ֺٻٺ׸ؽܼٽپݿ޿ٽݽ޶ܸܻۻ۷ݯݯ޴ڱگٵڰحٴڷۯڵ۵޷ܵݯٯذڳٮٯ۲ܱްܷܷڻ߽߽޿۸ܶ۱ܰ߶ڴ޶ߴ߷޹ܻ߱޴޴ߴ߱޵޵ߵ߱ߴ޴߹߶ܴ߶߲߸޷߻߲ݱݸݷ޷޺ݴ޵޴޶ߺݹ߸ߵߵ޵޵޶۶޶޶ݷ޲ߴ߳߷޸޸߸ݷߴݹ޹ٰѩ{ݽ޿߽޿޿߿߿߽߿ݺ۲Ζ~`xztcKC{[ImacxɣʟɝHH]' '&!'"*̨̪̪ΪήЪάҮҰϮүӵӱҶҲεԵִӱѹ׷ԲղմϳԵӲյӲѲӳίҪҮԭάʪЫͬ˥Υ̣ͧˤ˦˫˦̩Ϊ̡Τ̢ʢˤ˪ҧ˧ɨͦɩ̪ʭ̯ѲүҶбαѱΰжֵԵպԽ־ٽ۾ڼټռҸԷֶ׸Ӹּػ׻׸ҴزӳѱϴԮТrM}pO+0ve`bL7uXe&&APHJh^RyjB7;~}]qyriҼּزϱɎXlBJNLWr/+5DB:MZa̛ѠѪӨ֡ԓ͍ˆƊŒšȑǘʔȖȏŒċÊƇÇÍƏėĘǙŜɝɝɟʞȢ̢ǟʡΛͤˣͣΤ̢ϥ˦ΤɤͦǞŠɝȠɣ̣ɡ̥ʠˣɣɧɡʧɢͧΤΥ̩Ǩ˦̣ɢˤ̦̫ͦͪͭϯϳҴԯճѰѮϳүҪϱѮӱԳԲѶԴѵص׵ؽܻ۽ܿؽսؿݿܼ߿޹ݻܴڷݱݴ޲޶ݳۯ۱ٱݳܶ޵ٵڹڶܷڶڶڳܮܱٱܳݲݳޯ۴ڶݽܽ޾۽ܶߴ޵޴޶ݶ޳ߴ߶޳߷߳߶޷߶޶ݲ޴޷߮ݵ޳޺ߴ޴޶߶ݴ߶ܺ޴ݶߴ௽ҵݴ޳޳߻ߺ޵߶߶޹߶߹߽߹ܼݻ޼޺޻ܻݾ޽߼߹޽޽޾۾߿ݼ޸ݽ޸޷޻ߺݽ޾߸޳ݴۯ۱رԳӲѸѹҷִҬ̩̩̦ͥͩʢ̠̠TM` '(+ #'&yuɩ˪ΪЭԬѰϱϴӯӳֶصִֵҶӴַֹֹպֺٹطָԸյշֹ׳յֳձӱӯҮүͭΰЭѮѪ˪ΧΪͪΧ̪ͤЪɪ˥˨ͬͮίѩΫϬ̪˪ʭͯϭүϯϳѶѳϳղӸԹӵյָعػڿ׼սټؽڼֻؽپڽٻԽҹմӴԸԵеϵϲɴˡ\u)#Y]WVIYlnOOvtimεѲҫѣ˦χViSevwwic}yϒΝҤբӛ̍ƂŅȆĈƑŌƛ˗ȓǒǕƈ}ÆÐÑǖǚǘʖɐǛɛșȜƝșǘȠǞ˟ʞɞʡϤΣ˫ɧΤˤ̣ˢ̡ɠ̢̝΢ǛˣɤΠȤͤΤ˝ǡˡ̤ɞʜȣˢ̝ʟˣˠȣʬЩӫүҭѯүЮѫҬѬЫѰӭӫѫҩҧЭ̬Բ׳Զַ׷Իڽ׼޽ݻ۽۾ڿڿݿ߽ݶ۹۰ٲݰޭްޮݮܱڰۯٲܳ۶ݸ۸ݵܸٹڰڰۯګݰܭ۫خس׳ٻ۽޾ܻڶܭۯ۱ޱ߱ޯܳޭܱ޳߳ޱޱܯޭް߱޲޴߱ް޴޳ߴ߮޳߳ݴ޴ߴ޵޳߱߱ޱݶ۶ݮݶݱݱޱݴ߸߳޶۳ܰݵ޳ߴ޲޳޲޳ܭ͸޵޷޶߶޴۶߲߶޳޳߸޷ܵ޴߶ݳߴܷ߶ߴ߶ߺݵݶ޷߸߳޻߼ݺ޻޿߹޹߻ݼݽ޾޾߽޿߽߹߼߷޼߻ߺ޻ݶ޼޻ܹ޷޷ܺ߹޽޹۶ܴ޴ݳ۱ٮثխֳ֬֯׵ڵڵجԨѤѡΙ̣˧Τ̦̞CIV  !   ~^fxʩǪ̬̬ɫҭѴղԲձдѵָ״շٷ׳ٶԸֹյػյպָڳӶոմӲзְִַխѮѰѭѪӪέѨͬө̧̫̩Χ̫ҪΪ̥ͪʪ̩ͨ˨ͨͬέΪЫϰͭѭϮϮбϴԳұеηӺջֽֿݾڿټؾֺؽؼؼپֹٷԶնӳԶնַնӮѪ̕~rsfèάѰҪϐjk9U~&> @C?ŦϏɖќ֞ҙʑˈljČʀƊȄȉȍǑǒœȋčƋǑŌőƏ‘ȔȒɗΟʝ̠ɚțȜˠ͟͞əɡȞ̡ɤȤɢϥΧΦϩ̤ͣ˦ɡ̣ϥΨȣˣ̤Φɤʧɥˤ͟ΥͤϦʣ̥ɤˡ˦ˤ̢˥̨̧̩ͪЩѪͫΪѭѬѩѪӧЩըҤӫѪϤΥΧϫѬ֭ѳԲӸٱشٶ۹ٻڻۼݿڻۿݿ߻ܴڳݳ޶ޮݱެݳܲݳ߮ݳݳ۴ݷ۷޷ܼ߲ܵܳۮگٰܭڰܬܮݶ۶ؼ߯ݱݲޮݮޱ޴޳޳޲޳߱޴߲ߴ޴ߵ߶޶߱޶޶޵ܳ߮ߴܶ߳ݵ޶޷ݶ߲ܵݵ߶޴׷޶ݵ߷޶ߵߵ޶ߴ޻޶޷ߴ߶߷޸߳߹޸޹߸߽߷޷޷߷޺߻߽߾ߺ޸߽޽޻޶޽޽۶ݻܱݼݸݶܻݹ޲ܯبӨ֭جӪ׭ӪӮ԰ز۱ֳ֯լըϩϦ̩ϨϪЦϣOM[     "xj{_~}nΫаѮѭѮӱױγԵұֺض׷ص׺ؽؽٽּ۽ټٻٺٽؽټֺֻعٷնֶضմնѯԪӪӱӬΰήҮҭԬΨΫ˪ѪͬҬѰΪΪЭӬҪΰҲҳжӳӱҭҮͲӳչۻ׺غֻػغٻڽۿܾپؿݵٶعԹ׵ְӳѱѫϫПǬΧΪˬαұӮԭѥ͖_lNXsRfeo~GKly~ñΩϞΞѓ͛͌̕ʈȉɌɊƀŠɌNJȅŏȐDŽƀĉŎǔËƋŽĘȔəȝɜʛ̚ʜ̠ɞ˟ˤ͝ʚ˞͟ɣ̟˞ˤ˩ˣѫΧШɦ̦̤Ϥ̤ˣΨѣ̤ͨͥΧˤ˧ҧѤϥͧΫ̪ͤʤ˧ϣϥϨϪϭ̬ѫҧЬϥөѢУΤΞϠͥѡ˧Ω΢̪ΥΦѭӭӯձϰѰկѱӮӴֶӻؼۺٺڼٹݽ޼ݹޱ۶ݱܮܵްߴް߰ްݳݱ۰ܷ޷ܷݴگڱ۱ݯۮڱٯڱ۶۹ݻ߿ۼ߸߰ݱݴ߲ݲް޲ݶޱޯݲޮޯ߱ݴ߯޵ߴ߷߶ݶޱޱް޵޵߳߯޶߶۵ް߱ݶ޳޲߷޲ߴ߳ݯ߸߻ٴ޶ݷ߶ܻ޵޶޶޶߶߱߳ߴ߶߹߷߷޺߻޼߼޽޻޻ܷ޻޸޺ܹ޺ٹزشضضݶص۱ְٰ֬ѬԪӧիժӭֲ֭ٴԴ׮ְ֮ѪѨҩЫҩҫЪFJ_  ) vWs[}xi}ƪѱӲԮԱήֱضشصַֺջغظؼڻۼٽٽٽپٽܺؼؽھַֻ׸ָ׸ָ׶ӹӵӯԬбծ׮ЮЮҰέαЮҬͧҫѬίϯϮЫӯѱҮѱϱԴӯԴгҲӳԸ׹׼ؾڿۿػٿ־۹״ӶѴ԰ӯӱӰͬѬΧΪΨΪ̤̦Ϊ˫У̟̞͡Ɏ|u{Ƞȣϟϗ̒̚ʒˋɍʌˑ˒˔˓ʋ˂ÇƌđǑƇĐƒǒĖėǒÔŒƔǜŕʟ˜˝ˤȟȡ̟ˡ̛ʟʞ˟ʘɝǝˤ̥˨ˤ̤ΥФ̦̥Ξˣɩ̦ϣϤ˪ϤͨΦϣѨӪΥΤ˩ЫͨͨΪ˨ΥϩҮЭЯϮϪϦϤϠМ̢̡̠ˢțͤɟˤ˭ϪΪ̬ѩЪѯѮҲׯѱӳԱίҵֵ׸ںջּٻغڼܿݿܿݿݻߴ۱ݲޯޱߪޯرܯܯ޵ݵܴްܶڳޭܴܵ۵ܱܳ޳ݲذحٰڮڵظܼݽܽ޿޽ݹݴ߱ݲ߯ݰݴ߳ۮޱܲ۴߰ߴ۴߰޵޶ߴޱ޵߳޶߲߳޶޶ްݯݯ޲߲۶ߵ߮ݳ۲޷ݲ޲۵ݲܭܱݳߵ߲ڳ۳޵ݱ߭ݭװ޶޴ޱޱް޴ܴ޴ߴ߸߳޸޶޶޴޷ܴ߶߶߸ݶ߷ߵ޴߶޳߳ߵ߸޳ߵޱ޷޸޷߷߻߷ߺ߷߹߽߸ߺ޺߸޹޽ݹ޹޵ݶܺݸٷزذ׵ضرײծֱ֯ԯѧѭҬӫԨҨӱԯԭЮձլӬԭԯѭӯҳӫөRMZ0&!I7.vb%/%C0ΰӱѶӶֵ׵ֵַ֮ѵӷռ׼տݺؼ׾۽ؿؿۼټؼڽغ׶ѶնѷҵضѴӱϭԮҰұ̱үնԶѰѫѬծծԯҰҰүήϱѰбҰϮβѳӹҵշֻؽٽ׾ݻ۵׫ԱְӮѮЩϩͤ˦̡ͤ͡Ǩˡˠ˝ɞǝǠțƜÛęŕƛØb|ͨ֝љΖΑɒ˓̙ΛԟӝϞΙ̘̑ȎƋƍĉŽƏÎƈƐɓƑǔǕǜǠʝ˚̟ʟ̥͢˛ʕƚȗǖƑǖȟƖțɟʢ΢ϡ̤ͣͣŢФͤʤ̦ɤ˪ΩΨѧΥʨФ̨̧̧ΤͪФ̨̩ΩΪϫϭЬҪЩΡ͞Ƞ˟ɝǢǡǡ˞˝Ş̤ͤЩϪέѩѪΰаѯԮֱֲѷӱԲԳϷַػۻּڽּ۽׼ؽܿܽܿ޶ݸ۱ݲ۲ޮܮݫ۳ݭݱ۱߮ٳܰݵ߱޲ܱܲٵݱ۳ܵ޶ݶ۱دخٱڮڱط޸޻ݽ޽ݹٶ۶ݱݯݱ۳ۭܲ޲޶ݱݳ޴ݱڱޱްܮݰޱݰݰܯܳ޳ݱޱ޲ݱޮݳ޴ްݮۮݴޮ߲޲ݶ۱۱ܲ۶ۯۯ޴ݴ޴ݬݲ޲۶޳۰ްߴܲڮnkrܶޯ۲ܲݰݶ޵ݱޱޱ޲ݶ޲ܱް߮޴ݷ޶ݵޮ۱޸޳޶ݶߵ߯޵޳ݳ߹ߵ߲ݱݳ߶޶ߴݳ޴߷ߵ޹ߵߵ޹߳޶߸߹߹ߺ߷߻߶޶ߺ޹߶߼߻ߺ޻߻߹߹߹ݺ޼޹޺޺ݻݼ޹޻۸ܵشٯӯֱ֨ҮӮ֧֫Ҧ֪ѧЪЭЩҭ֭ӮԯԮ֬ҪЮҭҰӳְѰѬCKY0'K<+!  :&-'.qVx`K:&ϴӴԶӶֲնѶչӶֵԸԹؼٿ۾ٿھݽټ׾ؼٻظֳֹҵӷֳӱ֮ѱӰյֱѳδӱѴӲӮֱѮͳӰӲҮӰӳԱշӱұдʹιֵָֹټ׾־Ծսٽ۽ظٱ԰ѮѮѪͣɠǦʢǙƝ̡šɡŚ×ęĜĚǗĖƞĝǟÐFV~g|Ф׬ӟ՛Κ͛њҡե֤ؤأեәВˍċljƊƈǍǑɎǐ˘șɚʞȟʜѝ΢ͣ͠ˣɥУϟ̝ʚƚɛʛǏŘ˜ɣ͡ǢˤΣϣ̤͟ɣΤѡͤѧͦΦϦ˥ΤΦϤϥШΦϦѥΥϣΣѣˣϤҩѭЬϧϤТʝǝɞǝǞˣ˟ˡȟΣΤͦΪάίҳѮѶϲԶӵֶصؼӸ׳ֶظٹںڻټֽؽپۿܾ޻޳ٳ۰ݶ۫ݮޭݵެܫ۫ݫ۲ݲܳܯܮݰܲܳ۱۶޹ޱ۰ܰݰݮ۱ݰܳ۴޶۹ۼݸݸܸ۵ڰۯݳޯݮݯܵޯܯݱޮܱܱܭۯްݰݰ߰ݳݳ߳޴ޱ߳ޮݰޮޮްݱޫ۰ޱ߲ޱݱݴۭݰޱݳ߳ޯߴ߱޲ޮݶݳ߰߬omnܯܯݭݰݳݴޯ޴ܭޭ߲ݵޱ޳ޯݱ߱߱ߵڱܳ߰ڵݴ߳߱޲ݶݲ޴ݯߴ߲߳޳ߴݱߵ޵߯ߵ޶߹޷޸ߵ߷߳޵߳޵߶߶ߴ߻߷޻޹޽޿߶޻߻߹޺޺ߺ޹ݼݻߺۻݶٳֱرذԮجԯ٭֫֬Ѫѧҩѩե֧ҭծԬծְѬұկӱֱҲհԫXLHG4%[O?" viJ6)-*#%we`{o>&T2ѷѳԸӷָٶַ׸ٷۺջۺطھٿٿܿܽ׽ؽܽܺٻٹظطѸӴ׶պִӶֺշѷ׻ֶҸֳӶմնմӵԲնӲӳյֱҶ׳ֹնջһغٻټٺ׻پ߽ۻڱִӮάѡΞΟ˩ǞƚĠʘƢǢÜǛǛřžŸĝƚȜǚɟƊuХԨӞפסӢӤ֞Ӡ֤֡ئ֤טՑ̊ƐɆLjɓʌɓ̖Ò˘ƚ˜ɤˠ˞͞͡˥Ϧ̤̣ЩΥШϦΡ̟͠˕ˣɡˡʤϞɣˣ˥̦̝͡ˤ̞˞̡ʤЦͤϡΣɤˤҡΣͤʠ̡ɚʝɞ͙͟˞ΝΡХФϦΡ˜̞ȞʝʛȞˤ̨ͦΨ˩ήжбӰ֮ԴԱճԸֵظִֻּ׿ֺֻټڼغټؽۻۻ޶۷ܲݯܱݬޯܱۮݯ߫ݯݱݱݯݮܭ۲ڸݸܹڷܳݱ۰ڱڮݬݮݰްܱ޶۰ݹ߻ݵݶڱڮ۲ۮۭܩݭޯޯݯ۷޳ޱ߲ޱ޳޳ܲ޲ݵޮ޲޳߱ߴ߶߱޴ܳݲ޴ݲݬޮޭ޳޲ܱ߳ޱ޴޶߱ܮݬܳݱ߲߰ޱݮޯݯ۲޵ެGM]ٱܯݯ޳ޯݳ޲ݭ۱ްݴޮޱ߰ޱޭ߫޳ްߵ޳ߴܴݲݰ޵ݷ߶ݵ߯ܯ޴޳޶޷߶߳޸޴߲߲߳޳ߺ߶߷߸߷ߵߺ߷߷߶߶޲޽߷޽߻߽޻߹߼߾ߺ߻߼ݴݻ޸޽޽߽ٴٲسױֲӳرٮ֬խ׫ӨӥӱӭЫүֳ֮֬մծկ״׵ײ׳԰Գѫf}eVjK;kREvf]sRѹշֻԺֻػغٹٹٻؼڽټ۽ػۻݻڸػԹ׻ַعظڻٸعػջػּظԽػٷֶҲձճҴնַԹֹҶԵֹعٽظضطվٽٽؿڿݸسֱժХ̤ˤ̥˖ʡƟĝʞǙśǙŚȚėěŞȢšƟʟʓbrqШץѤդ֞שף֠ԡՠ֣֢؝ؠӖύɍȒǍȐʑǖ̝̓˚˘ɗǡ̟ˠ͛ЧңҥӣЦѪѩӬԬ֩ҤϛΣ΢С̡ˤΠ˦Τ̤ͣɜ͚˗ɛǜ͚ə˒ǚƗɜʙɔʌ̕ə˛ȚȘɒȓǗŗǘȘ˚ɝ˙ʠ̜̜̚͞ȢƠǤΤΩϢΩϬ̲ЮҰѮղӱѷԱԷ׺ֶ׼ھܾۿڿھ޾ڿ޿ݻܶڸܱ۱ۯ۴ݫݭްܯݱ߰ܰުޭߪ۫ܭ۰ڴ޴ܳر۲ڲۮܰݮݮ߫߰۬޲شܱܳݷ޶߰ڮۮۮۭޮ۱ޭ۳ޯݭٱްݵݲݳݶ޵߲گۮدܳ߸ߵ߲߳޴ޱޮ߱޴ݱޯޮޮ߳ޯ߮ݱ߱ޯ޲ܰݯ޲޳߰߰ݰ޴ۭۯ߱ޥPLI޲ޯ޲ޱܰݭ۱ݬߴ۵޵ޱ߱ܳڭۮ߳ޭݳ߰ޮݱݱޯܰܰ߱޲޲޴޴ߵ޴ݲ޹߮ߵߴ߱߶߶ߴ߶߸߶߷߸߸ߵ޶޶޹߶޹ߺ޼޺޸޹۷ݶܻݵݳܲصصܵ޲۱תֱ֫֫ҫԪ֯ҫӰְղձֲ׵״׵׷׶صضյԶҶնԸѶζζӶظӶҸԶضԷ׽ںطԷغ۶عٻؼݻپ۽ݾݽ۽ۺطػؼؽԼպضۻعչԻؽڻ۽׽־ٶ۹ظٵغظַӴ׺ָֺٺظظټԸոٷۼ׽پڿ۸۷ڼ֮өΧ̞̠˥˟ˢˠǜĚǡəǡğʞʤʟʠǠǜȡʞȑ}ХէաҠ՟ӣ֤Ӥџҡנ֤֣ؤӔʉljǍˌˏȍɘʕ̐ǚ̜̚˟ϝ͢ϝͤϢͤХУΨѨҮױհӥѥϤΩΥϥͣΣѤϤ̧̤ͤʠ˚ǛɕǏƛǘɏǜǍȎƖŊƐŔȎ”ƒÎȍǍÕǎ˜ʘǓǒÓŘǜɞǜʡΠʤ̥΢ΫѧӫӮӳԱѯҵѷձسӺڻڽݿݿ޹ݻ޹ڹ۳ݱ۶ݱڮڬۮ۬ޮްޯ߮ݯܫܮݮܷܲݴޭڮڮ٪۬ڰެܭݮޯݯۭݱ۲۰۲ܶޱܯخڴݭݪ֮۫گ޴ݰخܪۯݱܳݲڴݶޱ۷ۺ۷޸޺޵ݵޱ߳ޮ߮߯ݱޮݪ֭٫ݮޮݭް߭ڮ߳ݵ۳ۮܲޱޯ߱߱ްޮۮܰܬہ۲ެܭܱ߮ݲ۰ޱݰްܴ߱ݰܰۮ޳ܱޮۭڱٵ޴߰ߴ޲ߵݯݭܱްޯޱ޲ݲ߭߮ޱޱްݳްޱްߵ߮ݲߴߴݶ޲޲߶ܹ޶߶޵޷߷߷߶ݻ޶޴߱ݴ߶ޱ޷߶߶޸޶޶޹޻ݸ޹߸߶߽߼ߺ߸޸޼޸߷߹߻߹ޱ׮ر۱״۶۸۶ٯ׬ئԪԪիѬԫرֱֲձԶصֺոֶ۵۴ֳֵֶ׸ֻּۺٽֹԶڶֹ׷ֹٹعۻּٷֽػعڻܼۻ۽ؽٺڽؼܻؽػۻٻػػڽڼԼڽܾؽؽ۾ٿٻٹغعغعӼ׺پ׻ػݻټ׻ڹٻؾؾ߽ݻۼٸڶڮҮծӤѥʠˤŘ͚ȘɛƝƟ˜Ǟ˝ɟ˟ʞǜˡ̤ơʞȡ˦ʘѣҟ֠ӡўӕӠҡљѨդ֤֢ԓӊ˓ɍɏʍ˓Ǖȓʗ̛͙ʜˠΟΡ̠ͣͤ͢΢ҥХУШаұԳص֬ӨЪӥӮЫΤΤѥΥϡ͝Ξ˗ɟɜɞƗ˗ǖǑȕȒÍƎēƒđȔƓʒǓĕƗǏŎǘƙʜǕŔșȚȠ̟̤̤̮ѭЭΩήѭѰүҴѻطӼٺٽؽ޼ۻ۾ݸܳݱ۰ۮݱ۫ٳٰܭݭۨܫݮܮڭܰܰܮݰۯܰد۰ܭܮ۬ޮޭݬߴܴٮ۵ݲݯݲܵܯۮޯڲܪٰݬڱݵݳܴܻ޶ڶ޸ݹ۹ܻ߼޼߼ܵݲ޲޲߲ۮްްݮضܬެݯݬޮ߯ݯݯܰܮݯݱݴ߱ݱݲݯܰޯެݬۯޱܯܨΗڮݰܯܯܱޭܲ޴޲ߵ߶ݴܳݱޮ޵߮ݲ۱ۮ޴ޱݮݱ۱ޱްݲ߱޴߱ݱݴޮޱ߲ݱݱذްݲߴ޴ݵ߲ܳܳݲߵ߯߱ݳߴ޳ߴݴݶ޶ߴܶ޶ݹ޻ܸݷܶܶݼߺ߶޴޵۶ݶߵߴ޴޶޶޲ݶ޹ݶ޶ݶ޷ݶ޶޻޾߸߸ݻ޾ߺ߽߸޷߻޼߷߸߷ݷ޷޵ݶݺݷ۷޶ܶ۸ݵزد۱ܲ٭Ӱ׫ԪӰծְװ׳մնֲշ׶ոٻܺ۶ܴ׶ִѼպڽعֹػ۽ٽڿ۽۸غ۾ݽػؽؽڽ۽۾޾ݿ־ھۿؿܿݼھ۾ۿ۽ٺػֻԽؽڽۼڽؿټػؼܽտ׼ٿڿ߻ݷضزׯЮС̤΢̝ƛ̚˜ˠȏƘʘŝȟɞġǠʟ˟ǡ˦ˤˡ˟˦̤Ȩ˥ŤҢӥѢң՛ԚОӛФѣٟ֧؟֑ɍɊȌʑ˔Ȗ˘Ι˚ʠʠʟ̤ʢͥ΢ΤӢϤͦΣХϩҪӮֵ׷طײذӪ׭ӮҲҭήϰҪСΞΞˠʡΝΝˡΜʖȑƖŕɒǗƙŗ–őƑƔǏʓɔǓƘƛŘȞƚǓ͞˟ɠɠ̧̤˭ѯήѭбαѶ׳Ӷѹٻؼۼۿ޿߽۽޻ۻ۸޶ݳڱڳݴٱ۵دڰح٭ܯܬܮ۰۲ݮݱܳزٮٯگۯܰڭۭܯݬڮܱݮݶޯܳޭݱٮ۶ݲ۳۱۶ݵ۹߸۹޾߿޼ݵܵݳ޴۲۰ܱݭ޴޲ܯۮݭޯܱ޲ެۯۭޱ޳ݲݮ۰ڱ۴ܬܭܱ޴߱ݰ޲ܱܳ޳ޯٟ߯زܮڱ߮ݰ޲޳޳ܴܱܶݲ޲ڵ޸߳ޯݴݳڱٴܲޮڳڱۮ۱߰޲ݯݲݰݳ޳ܱ߳ݱߴݱ߲޲ٯܱ޲޴߶ܸ޶ޮޱݲݱܳݳްܱ߳޷ݲ޵޵޴ܵ۸ݺݷܷܺ޺ݹ޼ݼݺ޽ܷܴܸݵ޷߸޺߸ݸ߱߸޶߶޶߷޹޶޻޽޷޹޽޽޼߽޼ݻ߸߻ݸ޹޻ݽ޼޹ݶ۸ڱֶܳܰصرٱٯخحذحׯֱֵ׵ص׶ظֹں׺ٷٸֻۼؽڽٻھػۻؽܽݿܽݽݽܿۿ۾޿۾ܾؽۿۿھܿ޻ֵ԰ժάӤѣΠ͟˛˙ɜǙ̗ʠ˝ɜǞƞɟɡȡƠ̢˞ˤɥɢ˨˩˫ͩͩͬ˰ѡա֟֡֠Ϥ՗ϡӣјӝ֢֡ՐɍȋȖˑ̖̐˗ΙњˤͤͣϡͥЪӨӤҡћ͢ХϨͩӪѭԲճ׵ٹسصܲկӮѪ֯Ա֮ѩѦΧϥУϣΣΕΘʜɖ˚̞ƛǘǔɗȝǙǕȖƕɕɘŘƚ˔ə˜̣ɞɞǡ͢ˤ̤ͩѫѲѲӮβӵرֳصӵֺڻ۽޾޿޻޺ݹ۹ٶܶ۴۰ڱۯٰسدسۮگٮٯۮٲݳٴڰݱݴܳزװڮٳ۳ڮۮݮ׮۲ܶٱܶ޷ݳ߶ܴܷݶ۶ۻܽ޻޼޿ۺ߲ߵݳܴޱ޶۳ۮۮٱ۬ڪް߮ݱ۱۲ޮ߮ݭݮ߮޶ݲ߯޳۳ݰޯܴ޲߱ݱݱ۱ݮܩ˳ݱܰݵ޴۰ݱݴ߲ߴ޸ݸݶ۸ݺݹݸݱݶۮذۮܮޱݲܴݱ޳ްޯݳޱݰܴܱܳۯܱݲޱݮݳݴ߶޳ݲ޴߳޶߳ߴ߱ޮݷ޴ݴޱ޲ݵ޳޳޶ݶ߶߶޻ݹ޻ܽ޻۾ܼߺ޻ݺݼ޻޷ݷݶݷ۵ݶ޹߷߶߶ߴ޴ܶ޷޸ߵݻ޽޼޻޿޺߽޻޷߻߾߽ߺ߻ݶ޷۱ܱ۶۴ܵٵٵرֵ׬ֱׯٱ۳شضٵַٴֱ׵ڹڸ׷ٶڻٻټܾٽۿݿۻ޿ܼۼݾ۰ثԧѤСΠɝƞ˚ʗ˙ʚǡ˟ǝˡǡɞȢȢ̦ͧʤˢ˞ʥ̥̦ͥΤ̫ͨϭͫаҢ֤ԣդ֠ќӟ֜ԜФ֡ӚӠՒ̌ɓʏ˒ːΗ˔̚˟ͣΟҢџϡӤӧզѢѝ̡̝ЦӥӪҰѳ׵ֵػغ׹ڽٵհѮԭӮӪѪӪծծֱԩѝ˜̠˝̘ɖȐƚ̘̜˝ˢ̝ɗ̞ʟʜ˚ɘʜǚ˞ɞŢ˟ʟ̠ɤͬЩϰѱԵҴرӵԵٶֵط׺ؽܽۿۼݺܸ۰ڲشڶ۱س׫ӯخ׫خ֪ת֮֬֬ׯج֬֯گٯײְذ׳ٳװصڵ۰ذٮڮخׯ׶۵۹ڻݽ۷ݺ۸޻ݹ޿߼߶߱ݶݱݵگݮܭٴڶستګݳ߯۱ޱ޳޲ڮܯ۴ݲޯݲ۱ܮ۰߱۲ݰ߲߳ݵݵۮկڲܶ޳ݳ޶߶ݷݶ۶ݸݺ޻ۻܽ޻ݷض۶۶޴۷ٱ۲ڱ۳۰ޱݰݮٵܲۮرܯܰ۳ۯ޵ܳܲݳݵܴ޳ݳܼ޸۳ܱ۳۶޷޵޵ٵݲ޵޴۱޶޳ٵ۸ܺܿݻ׽۽ݾݿ޿ݾۿ۾߽޷޹޼ݼ߸޶ݱݺ޶ݷݵߴޭݸݺݷ޻ݻݸݻ߹޼߻޸޺߾޿߽߿޼߽ߺ޷ݷ۶ܸض۷ڳطٳضػ۶ڱ۳ٳ۵ڻڷڶٷ۶ٹڹصֶٻںؼۿܼڼؽݿ޻ܳدѦϨ̧ˠ˛˝Ǚʙ˛̜ɞɡ͛˚ȡ̞Ȝǡ˝ˢʠΤ̡̣˦̩ΧЫ̮ͮͪͮѮͱҡѣ֢١؟֠ӜդԙԞӟӡաסәˏɐː͑ʖɠ̞͢љ͟ѡͥѣУҦЦѢ̞ϠРѣЧӮӰӳճմյ׸ڻ޹޶ܱدԱ֮ҭѱѱѰ֮ر۰ӪӤΡΤ̕˘əΙ̜̜Ν̞̟͟ʣ̟ϣΟ̝̜ʚɚʛ̡ϡΦ̟ʣέΩѫӲַٲ۶ڳٱӵնض۽ۼ׽޼عݴֳڶذֲѮԩԧիԨԭҩѫϫЧӬ٪ث֮ԮӫҭӰ԰ددٵױزضشسڰְ׵״ֶزشַ۶ٸۻۼۼۻݻݹ޽߽ܼ޹޶޷۶ٮٲحزذٵڳڳ۴ܱرۮڮݬܮۯݰ߱ݭݯޱ޵޶ܶ޲ݴݷڲݱ޳ٸ޺޻ݸܹ߷޷ߵݺܿܽ۽ݺݽ߽޽ܻڶݻݻ۸۶ٴܷݵݶܮ۴ٱڴڰڲٱ۵۲ڲڱٮܶݳܴܶܳݵݴ޴ݴݶ޻ܻݶ۶ܵݶݹܺ޸۶ݵ޳ܳ۰ݱܶ޺۷ݹܻضڻݼ۽޽ܻ޿߻޻߽߹ݸ߶޵ݷ޷ߵݳݹ޶ݷݽۻݻ߷ݽ޽ݿ߽޻߽߽޽޽߻ݻ޹ݶݶݻܴ޺ݺ޸ۺ۹۶سڴطڷ۷۹ݻݻܺڸٹزڵظٺڻۼܼܿ޷۱ծΤˢ̡͚̕˝ʤȜɖ̟̞ʚɠΟȝʡʜˣͧʣȤΦΡ˧ʣѤѨΨ˫ήЬаӮήңԤ՞ա֗֜ԠןӠљ՚ԠΛԛ֘ѕ̔˓ɒ˖ʖΟ͛ϞФЦϢͨҦФϥңҧҦҧϥϩҩҭֲشںڷعظ׵۶ڹֳյز׮ҭիӯֱִض۲ضղӧҢЙ̗ɛ̗Ιϡͨ΢Σ΢ˢΤΤΣϟ͡˜̡̝ϡΠͣϥѪҬѭҵַ۸ٳڳطڸضظڻٸݽݿ޼޽޾޺ݴذ۴خժ֥ԥ΢ΤѫϥԨѨͪӪӬѬ֬ױױ֮ׯױֵ״׵ص׹ܴرֵնմ׷ڸܷ۹۸ۼ۸ؼٺݽݾݿݼܷݹ޺ݹܻݴܵۯݲۯڱڱڱش׸ضֲܯݱޱܲݱݳ߯ۯݳݴ޴ݱ޶ݷݷݺܽܺݷ޷۸ۻݼڹݽ߼޼ݽݼ޼߼޽޼޾޽޽ۺ۸۷ط۴ٶ۳ٳ۳ٳڲززٯٵݴڵسݵ׵ٶ߲ܲܶ޷ܷܷݸٷۺܵ۸ܻݹܽݷ޸ܶ۱ް߱޳ݴ۷׶ܹ۸ܺڼۼ߿ۻܼݾݿݽܽݻ߼޽޽޹ݶݶ޵ݱ޻޶ݵ޻޶ڷݹݹݽ޽޾ݸݸ޼߼߽߽߸߾޸޹ߺ޴޸޶߶޺ݽ޻ݶݶ۹۸ݶܷܷڹۼڿټۿݽ޽ظص׵ٵ۷ڼۿ߷۱اѧϠ͠ʘǞɝ˝˟ȝʚɛƛ̚Šʛʛʡǝˠ˦ɢͧͤΥΦϭѫϫΫѪϮϮҮѰҞРѣդ֟ӟ՛Қ֞ӣ֡ңϚМРЗΕΘΒ̘̕˟̠Ξ̤΢ΤѣҪΩӧѣϨ̧ͧЦҫүЮӲյعڽۻݼۺؽؽظִسֱӮѰԭӵԶغڴֶ׳յմԠϟɡ̢̣ΨΨЩϨͪϥҦͧͥΤϢͣ͠˩ϧ̤̩ϫѪԱӳԵӻزҴղնֻٻؼսٻ޻ۻغۻ۷ֲխժ֪ѫ̪֨ɣ̡ˤˤΪѤѪͪҪӫЯ׬ձնصֲֶ׶״ԶڹնԸعػٻսػؽؽڻۿ߽ڿڷٴٵ۶ִص״رֱٰ֭ڶֲֻշ׹׷ָٶ۹۷ݸۺݳ۶ܱ۶ڷ޺ݿ޿ݿܾܾܽ޽۽ݿټٸٵعذ׷ذٳִ׳ذֲֳس׷ٶڶڶطڸڵڳܶݷݼڸػܶٶܶظٽݻܽٸۺڶݳݶ۶ܶ۸صڻػڽھ޿ۿݾ۾ݿٽ޼ۺ۸ۺۺܻ۶ܺݶݹܹ޻ݽܽݻݽ޿޺ݿݾ߿޼޾߶ݹݼ޹ݷ޷޷ݺ޹ݺݻۺܷ۸۶۷ۼۼڿۿܿ޿޽ۼڻٿؾ׾߽۴֫ѤѫϠ̟̙ƙƞǞȝΜ˙ǟ˜ȜʢǢˤƤ΢̥ɣʨͨ˩Ϊˮѧѫϩή˭ͱϰʳҥ֟֙֡ןԠԘӖӞ֢ӟ֜֟՜ӜҜԛԞәΥҦҤӣХӧҦΪ֬ժ֪ԫҩЧԪҪլԮׯհַٸػڽݽܻݹ޼޽ݻۺۼ۷ׯװԯյ׵Ժ׷׹ܷظݴשӤ̠͡ӪӤҪӬөҭѮҩӪѨѦѥЦЦϨϦΪЪѬѭӮֲزױٱڳնڶٷ׻ظ۽ݽܻ۷۳حج֤֨ѩӪӫѪ̨̣ѥѥԨԪӮӱϯխӭٱ۱ܶٹٺټٹٺ۸ڷټۼٿ޿ݽغܶ׳ٰ׵ٳ޲ٯܲ׮رִصعؼۼ߾ܿ޿ںڽݽ޹ߴ۹۹ܿ޿޾޻ںڹضոѱֲճٳڳڴسص״شعݹ۶۶ڷڹ۶ܷڸۺ߹۶ٹڶڳܸ޻ܽ޺ݷ۳ݶڷ۶۹ݽ޻ۼ߿߿޽߾޽޻޸ݻ޶ܹݷݸݹ޹߷޽ߺ߽޾޽޾޿߶߸߻޶޻޵ݶ޺ݹ߿ݼ޻ܹݷݷܺݾ߾߼ݿ޾ܱ۬ЧӥΤΣ˛̢˝̡͚̝˛ˡ˟̝ǝˢͤͣΠΥʪάѪΪέЭҩ̭ϬЭΪѯѯ̲ҢР֜ԡ֟ԝӜ՟՚ӡ֢ԜӝәќӞՙОӞϡϨӨҨϩѭ֭ӱְ׮ձ׳ԮԱԱְִԲرִֶٸٽڼݿݽۿ޿޽ݼ۴رزְֵֻ۽ֶܻض֪ӜΠΥӥҩԯүӱֲմظկ׫ԬԭҨϧЬЬҪҨҬҰԲӱֵճ۸ٵױ۶ֱֶֹۼܳ׶ذתխԢΦΧШЪӪӪΥѩϪѨԫֳյѷװٰ״ַ׶׵ٶ۽ۼܹ۽ؾ߽ݽٺڶٰ״ֵزַڴٳִܴظںپۼۺۻܽݽ۽۸عڶ۷۸׶ط׺ٸڹ۸ٴعٺںڸܶٹ۽ܻ޻ڻ޻ۻٹݹڻܻݽܻܻݺ޹ݹݺݷݽؾݾ޺ݿݾݻܺ߾޹ݽ޿޿޿ݼ߽޶߷޽޾޹ݺܻ޵ݻݺڻݼ޵ٲԯӮӤѣ͜ˡʜ̝˚ʞ̝˟ɠ˥ͧɦ̤ͧΪΰҫϫѱԵӰѬШЯҮЭέΰӯϴҞӡԙԞӞԟҠњӕ֘џԝӗӚӘїԟ՟ԟ֞ӞХѩ֪ӯְر׭ְصַ۵د׶ز׶ٲٯصۺ۽ٷڶ׷׵ٷڻٸ޹ݻڲתў΢ѤѢҧէӭԮϲմӶԴװӮӱЮҬҭѰүԯխԪ٭ڰسֱֱֳٵݵ׺ع۾ټٶֱ֧֮ժӧ֨ЩΨѨЧѭҫѭѪӮԳַ۶׷ֵٱضٸضع׸ںڻܺ۾߹ܷ۴ٲص۶״شֵխ׷سٸܻ۽ڿ޹ۺڼۼݾܷܽ۷ؼٺ۹ܷܻڷ۵صݳ۶۸ݷۻܿݾܼݻݽܽ޻ܼܿݽڻۿ۹ݶ޷޽ݷ޺ۺ޼޿ݻ޼޻޺ݻݽ߶߸ݶݺ߻߽߻ݺݹ޻޿޿߿޾޼޻ݽܺ۳۲حثӬӤΥΣ̣̤΢̠˝̢̞ˢ̥Ϋ̬ЭͯѮѭϱӳ԰կҬѧЭέЯ̰ҮδқΛЗјЙϘџӡϞ՜ПНӗҙћӠԙ՚ӞќҡҥЫӰ׳ִָظظ׸ٶص׳նֺظڶڹָվضشسֹֻ־۽ܽݾݽޱ֦ϦϧΤϢЮбԵ״ն׻׸صճر԰ӮҰӱհӰֱֲԸڶ׸ձ׶ӵѵٶ׸ؾٽ۽ݽݿݷٲխ֮ԮէӭѮԬЮ˨ΪͫԪ֭մػԺָش֯״׶ٻ׹پֽ۽ٿ۾ںٸسرײֶ׹׷׵չ׸׻غۻڽٽ޼ݽ޽ݺܹڻػںۻٺغططٹٿۿܿ޿ܽݿݿ޽ݽۺܾݽ޾ݻ߷޽ݽݾٺݿ޼ݼ޼ݼݻݹ߻߽߻ݸ޻ޱݼܺݿ߼߽߻ܿ߾޿߽ܾ޾ݻܾ޽޿ܽݽ޷ܶٲڳٶױԩӧϠ̞ͥΠˠ̤Ƥ̩̦ΪήήѱҰѱеӲԵӳҰϭѳҵѶҷѳвηӛҝОћϚМіѢӞОיҠѝНϛљ̙ОӜњҞѓФҩժֵ֯ۻۼܻݵڱ׵ٶش۹ڽۺۻ߻۹ڽܿݿݷں޹ۻܻ۷ٱ۩ؤӣդѧӯӸػٻܻعܵױٲֳԯӶڳشԱװմٴ۸ٷٳִٷ۸۶ڻ۷ۻ߿޽ݲخְצѩѪӭԭ֯׭ЫծϮӱ԰ٸ۹ۺַָ׷عطٻؼ۾ݾܶ׷طس׷صڻغڻڼڽڿݿ޿߿ݾݽݺܼڼ۽ܼݸڽۻعܼܼ߾߿޾߿޿ܹݺھ۽۹ݽ߿޽޽ߺ޻ݾ޿ݼ޺߻޼߾ݾ޽ݿݼݻݶޱ۴ܸܶ޻ܻ޹ݹݼݼܽܽܶ۲س۵ܸױׯөҩѦ΢̡ϧΥ̪ͮάϩЭӱֲճֹ׻ٺոԷԷӲӳзҸԹԵҶϷӜΟϜҠԛӛљӛգ՜Ӡ֜ӚآԟқҚљДԟԞӒҠӛ֜ԝԪ٫٫۫گڷٲڵڶ׹ܾݼܸ޹޻޽߶ݵ޳٪קڥدۮ֤֤֤ۧڤաפլسڸܹܻڻۻܴܶ֬֯Դڭձֱڰرض۷۸ٺںݼ۹ݺڻܽܫժըتԪԫԫ֯յҰѪѱԱӲֶֹٽܸٷ۱׶ո۽ؼܽڻ۾ݽ޽ݸݸ۶ܹ۵ضغ۽۽ڿݾۻܽ۾߿߽ݾ߽ܻټۻ޺߿ݾߺ޾ݼ޻޾޼޿޻ߺ޽ߺݺݶ۱۴ݲܯܯܰݲݳ۵ܹ߽ܳܺ߻޿ݽݽܴرٮثթҫѫΪͰѯԱӱճұѳӴѹֻܾڿؽؼڽظ׷׹ظ״ּҺӗ˟ЗѕїΜѡӌЛϗӚϙКϕєїΙўљНљΗәΖҖҝϚҝӜѠԧԨץ֣׭ٷ۽ܷۭڮױۯ٥ףݤ׫رڿݾ߾۵ݮܠ֠Ӣӡգלդ֡֟ӝԙա֟ԜӟԦӭԵٷۼܼڻڶ۷۳ֱدԫԨԬ׮ֲخ۱۱ִ׳׸׻ֺ۽ܿګժҭԪΩѫϴԱѮ֮֬ϭӴԱԺں׾ݾ۸ضֺ׺׽޺޼ڹ۶ٵس׵ٶضۺڼܿ޻޾߿޻߾ڻܼ۽޺ݼܺܺںڶڵټܻ޺ܼݿڽݽع޻ݼ۶ݺۺۺڽݻ޽ݿ޺޿޻޹ݼ߿ݾܿݿ޿޹޸ݰٰܱڮٱضڷݳݷܻ޶ޱ۴ݳݱ۱۰ܱٳܱ۱ڬ׭ح٫ح۱ܱܰڱܱܲ۷ٺ۾ݿ۶۲زر֯ӱӲЮԶֵַӵѲӲѳӱ׷ھؾؽڿٿټھظ׽׻վӺҙΚОΛΛϟњҟЗЕԜҙДΓΘєљԗӏЖБѕΗљқџіәҜҙқћҞӕӟ֨٥ڞҜӠԞԟբӞ֒כ֣ձ׷۪ڰۯܤ֡Ӥ֜ӡԢԡԡ֞ؖ֠֠ՠԞ՛ؚՖ՝Ӧ֫زڶܻۻۺ۹ڵٱر֮իԩҦөԮײ۲ٵܳں۷۽ܾݽڴѻ׺ػڳ٬ֱ֫Աӱزڰضسضڻݾݾ۾ۼ۽޽ܼ޹ݵڴزٵڸڻۼ޾ܻ޾޽޹ڽ۹ڸݷݷݹݺݹܻݻݻݿ߷޹۹ڹܸظݻݿݾݽ޿޽޿޿߻޽ݽߵݱޱݱ۵ܮ߮۫ڰګٱݯٱڲڰ۶ܱܮܱܱܳ۱۲޷޻޶ݲڱۯܱܵ۱گ۱۱۰ܯ޲޴گڮٮ۳ݮٯܮݱܯ٭ٰڮۮڮۮۮܰڮڰܳ۸ݹ޾ݷߴڸڵڵۼغؽ׽ݿٻؽڻ׽ԼֽؿԽӼԗ͛ΖҖ͡ϠΗϖ̔ВёҗЖϖϖϕϏЋΘђѝКҕәϗД͛ўҔћҎӚМӚӛӟњҠӠԚԔҘәӗ֛֕՗әӜӠ֜֡֠ԞՙӛӟӟҜԝԞ՜֚֠֡֜՘דӞԜӢդԬ׳ٺ޺޼ۻٵسذخתլԤԫԮذٶܶݸ޸ݻ۽޻ݳݮذֲֲׯش׸ۺٻڹغۻۼ۾߾ܺ߳ܳٳڶشڸۻؼ޾߾߼ݿݾݽ߾ݿݼ߽ܺݺۻۺ۹ܹݷ߷޹޸޼ݺ޽ݻۺܶݵڳ۹ٶ۸ضۻؼ޽޿޽ݻ޾޿߻޾ݻݽڽܾܺݸ޶޺޹޻޽޻޾޺ݳ۴ݱ޳۶ߴݮڮܱܬڱݮۮܬۮ۴جۮٮٯ޲޵߶޵ݵٸݾߵ޺޶߲ݯݩ٭ڮث۳۱دݫݱݳޱڱذدۮ۪۬۫کح٬ڭۭۮ۬ݮۭڮ٭ۭثڭڬ۫٪ۭ٩ٮگجثڮ٬ܭۮۭٳٷ۵۳ݳݳݹݻ۽ۺպԗΡљћҚәє͟Йϒњқѕљϖ̖Ζ̘͗Ύ͑̓̕ӒϘҘҘјњϝԚӗӝҗНΟКҙӠҞהԔҙә֚֔ՠ֟מ֟՞қћӛԝ՞֜Ԟա֠՟՝՗ћךӘӝԘԚ՘՚ӡԦճ׻ܽ޹ڹ۲׬׮֭۬٪֤ӥլد۸۳ֶ޺޻ݻ֮֬ױٮخֳعٽۻۻغڽݾݾ߳۱ڲڱڶ۷ڹںܻܽݶܼھݿݻ޹ܸڷݺ޹޵ݸݺܷ۴ݷ޻ݽ޺ܼݶ۷ܹطڶٸܸ۶ݹܶۻۻ۾޽޿޿߽ں޻ݻܺزܶ߷߻޻޻޻޺߼޸߶޷߾޳ޱۮ߶ݫݭگݴ۳ܱܭۮۯ۰ۭܮװ۰ۮ۬߬ݬۭٯܱ۴ݸ߰߭ܮۭۯڮܹ޺ްݫݱ۱ڰܮۯ۬ۧ٫ۯݭۯ۰۱ڭۮܯޭݮۮت٬ۯۯۭܫܭ۫إت٫٪ۮܮܧۨ٫۬٫ڮۯڭ٫۬ݩۣש٪۪ګ٭جܭ۰ڰۯخ۱۱ܲݸ޸ݼۼӘ̟̠Λϛ̕Λ͖ΓΓΔϝҠљΖΘϗΚΕΖΓΗЛӎ̘Ξ͜͜ΙїЛҠўΚ͚ѝԛҝџҘԖԖҖӖӔӝ՝ҟҜԗ՜ӕћӜѝԡ՛ҝԟՠџԞӡԜӜ֟ҡ֝ՖӖӛўңԲ۸ۺٷٲܯڨ٥פبڪکثծװٱ׶عݻܶؾ۽߿߫ӤѪӪ֯ױٹعڻݻܽھݰܱٯܷܷڻټ۽߾߼ߺݽۿݿػݻڻܺ޽޿ݼݹۺۺںݽߺ޺޸޴ڴܰٴضڻں۹ݸ޹ڵػֵضسٸۻܽػ۾޽޿ݿݼܽ޼߼ݸܶٹܹ޶۸޹޻ݽ޾޷ݸݷݻݽ߷޹ڱܮܰ۴ݮݮۮڱܯۮݱرުޯۭ߳۱ٮذٰۮٮٮܮگ۱ܱܮٯڮܮܯܮد۱۪ۭ۬ٯܮݯڭװܮ׭ڬٮگ٪۬جۮدٮڮ٭ܮݩܭڧةت٬٪׮ۮܮܮګۯۮ٫ڬ۪ܫګک٬ت٭٪٬۪ݩݬڭ׬دڭ׬ر٩ةۮٰحۮٯدرݰ۴޼ݿԚΔΛ͖̘ГϗҔќћ՚ΗφỪ͓ϚϚϚ̗͎̕јҕњϜ̝̜̙͔ОћўѕϜқӗўҜҚҟқӞҖҚҕԚӘЙќҕҘҗӚӒҕӝԔӛԠԘ֜Ϝ֡֗ԝқԡԟ֞՝՗ԟէت٭د֮ڦ֡Ӣٝԣզץاٮڬڮ۱ضݶܼۼݾܽݽݾؽ޿߿ܪ٥ҨԬֶ״ظػٽ۽޶ݳܴۯ׬ٳٺݽ߾ݿ߾޼ݿۺ߿߶ݷܴ۶ٶܹݻۺܹܷܹܶݿ߾ߺݹٶ۷ض۲ڲ׵۸۸޳޷ݶ۷۶׶۹ܷضڻݺ۽ٽؽݿݻݿ޿޿޾޻޿ݾݽ߷ܻݻ޴۷ܵ޶ݶ޹ۺݷݻݻݻܶ۹ݹ޻ݻ߾߶޳ܰܵݲ߱ݱݭڱܮݮܭۭܮݭۭ۬ڭۮݮݮݰܮگڨڪ٪ٯۮ۴ܮܭܯۮܵ۬ګ٪ۮڰ۬ٯت۪ګڬڭܮ۫ڭ׬٩ڭٮۭڭܮۯۭثح٬ٮگ٭ݭۯ۪جتتثګڮ۱ۮ۫ثجڪ׬٪٭ڭ٪٪׫ب׫ةخ٬תث٪ګجث׫֩٭ڭڭثخدۮڮ۱ٮݱ޲۵۽ۿԚ˛͛͡ϖΗ̕ΜќΛϘѓ̙ϕΘ˘˕ΞΗώ˘Θ̞͛Λ̜͟ˢʗЗΛϜЛΠООҙϝКϜЙќҟѝќӞӛўўКћАϘѝԝӖНѝўРҟԡѠҙўӚОӚԕԞԜ֜ԚҝѠ՟ՠԝ՟՛֝ӠӢҥԩԥդةڪڮׯٳۻڽۿݽݺܻ޻޽ݾܻݹܼݻݷܼݽߺޫݨۨبئ֨ׯضۼ޻ݿݶݭ۰ٲگٲٳؼܾ޽ݺ۸ݻܼ޼ܺ۽߿ܻܺظ۹۷۴۱شٲ۱۵ݷ۴۱۷ݵܻܶݹ߶ݻݶٳدضڴٱظٶ۱ظٸط۴غ۹۽۸ۻ۹ܺݺ۽ڸݺ۽ۺܺغ߾ݿܼ۽غֻ޻ۼ޻߶ٵ۷ٶٹݸ޺޻ݽܸ޺޷޶ܺݸ޴޳ڮڰخڮ۱ܱܰޭٱڱۯ۱ۮۮ۰ݰݱۮٰ٪׫ڬۯڰ۫خٮحجٮ٭جٮڮ٭ت֦ج٭٫ثٯخ֬ڬئ֬٪٭׮ٮݩ٬٬بحج۪تحڮخשد٦ث۪֪ت֪ת٤תש٪֪٬ڭ۰٪֬ש֭שجگ٧լդդծ֧تح٪׮֭تծ׭׬ثٮֱٮשթد٫׮֯ܯ۱۵۱ٵھؾԚΚјЙϙ̓̕ΚЙϡКѠϛ̘̗̑˖ϖЎϕИ̕јΝϗѝΖ͖ΜϟЖΚўСўӞӝӝҢЛҝӛџОўԝӞОҚЙѕњҜӟҢ՜ўџѠѡЩӥӤ֜՜Ӡҙ՘ӛ՘Ӓ՚՛ךқӜԟԟ՟՜՛נכԝӞ֞Ԡסڛئت۱ؽ޾ܽݻܸݸݺ۽ܻܻ޻޾ݽ޾޹ݻ޵۱ܲۮۭ۬کا۩گٻ߰ۦۨؤڣ٥֤ۡۢ֞حٱٻ޼ܵ޸ݳܮۯگ۰دٵۼݻ޽ݸۻڽݼ۽ۿ߿޺޻ڷܵۮܳݮثح׬۱ڲ۫ݭܲٴݳܴݳݲ۰ܫٯٱذشٳܱܶ޻۹۶ض۸ټݽ޿ݽ۹۽۸ݶ޶ݻܼٷٷع׼۽޼۹۹ݻ߻߼ݹ޹޹ܶ۷ڶݸݷݸ޻ݽݼݻܽݵݶܹٵݯ۰޳ܯۮ۱ۮ٬ڮۮڰݮܭ٭۪۪۫ݱݮۯۮح٫ڮۭڰܱ۪װڬج٭ܭ٬۬ܭ۲۰ګج۪ڬ۫ڪٰ٫ڮ۫ګ۫ܩ٩ګۭۯܮ٫٫֩קڪخ٨׬٪ا٬ۨתت٨ڪ٭٩ةګث׮تخۥ٨ث٫٪٫ګحثץج٪تڥר׫ت٬٬ڭحڮثת٫׭۱۬ۮد۫خخ۰ڱ۱ڴ۱ܳݵټӛˠ̟ϣ̚͜Λ̤̚͜͞РΛϜΡ͚˙Й̚Зʜ͖Ι̝͜͜͝˚ͥ͞ΠќϟСѡѝѣңϠРѠΣСϞЧҟФӝУѣΣҠѢѤӨեѦңѣӪѦөը֤ңӤӤ֜ӛқӚӛҚНԠѠԝӝԟҠՠբ؛؞ԜԞ՛נՠ֞Ӥӱسݻ޺ܮ۱ݰٰݵ۲ڳݺݺ޺޶ۮݯگڮ۫ڠڣףס؜أڠ؟֢ר۬ݮ޲߰ݧ٢؟ء٘ՙסעԤؠ؝רر۹۽ݴغ޾޻ۺ߷ܳܲ۲ܱܬܲۮتڲ۷۾߿۷ݷܶݻܿ޽ݿܸܽܺ۵ڱر٪ثبحګگ٫ک٪حګٮݭܩ۬٫سٯ۱ڴرٱ۶۷۹ۺڹڹٽٽ۾ݼݽڻٺ۹ۺٹ׻ػظۻڽ޺޼޼ݼݽܿ޽ܽݾ޹޻ܻڻ޽ݻ۷޻ۻݺ޹ݻ޾޻ܷڶܳܰ۴ٴݶܰް۰ڮ۬ٮٯۯܱگڬڬ٪ۭخ٫۰ذڱ٪ګڮ٪ڮ٫ڪزخحجختتڱ۪خܭڮ׬ثح٫ګٮۯ۫ٯ٩٪ڪۨڬخר֬֩ب֫ڭ٪٭ڬڮת٨ة׫ت֭ױ׫׭֥Ӧժج٩ت٭ڪ٫իثԧ׬׫ت׬ڭ٩ثج֮֯ٮڱٱ۱حخծدګٮ۫۱ܱٳٳղض۲׮ڷٳ۵سٶ۵ٽܿܿݽݷطڼڽݼۼڻڽڼ־Ҕɟ̛˙˛͙Ρϛ̠Ξϝ˖˙ˠ̡̗ϛϙ̓ђΗ͖̜̝ΛМϙΙ͡Λ̝Ϡ͠ҟѤϟΤѣΡ΢ϢѢңПϝ̠ΠСΤΧѣҥС̢̤Υ͟ϠԤԪթЪѨԦѤӤգ֣դ֣՜ћќНҞҟӠӠաңӧաןԢբԥ՜؛֝՞ԞԢӟԱڶݲکٟםأڤ٤٣ڧܪܪڢۣ֤Ӥ֟؟֟ٚל֛֟ѝ֝՜כ֚מנ՟מ֝֟ԛממؚיآל֜ם՝֤ڭ۹޷ݵܷܲݸ޻޵۳ۮۮڭۭ۰تجڬ۬٭ٴۼݹݺ޽޿޽޻ܸݺ޽޸ްصطٸܾ޽ۻݶڹ۴ڮڭܮث٫٫٪٨ت٫٫ڪک٩٨تثحڭ۲ڲدװخ۱ܷݳ۶عܼݸٹؾݽ۽ؼֻغطػضغ۾ھ޺طݺٻݶܻ޽ݿܻ۸ٸڸܻݶ߹߼޸ݶۻ۶ݸݶݷ޳ڮ٪گڮۭ٬ڭۭڰجګګ٫۬٭ٰܭۮ۪حختܬۮڬٯڮةګح׫خخح٪حۥةӮج׬ک٭٫بتרب٩תککګثګשժת٦تةج٪ڬש٪ةتحک٭٪֤ج֫׭׬תخԩج٥פק֫֩ةخ֦ث֧Ԥ׫ؤզجج٫צج٭ׯԯװڮد׮֦֮׫կدٯٶڴرررׯسش۶۸سضضڶٷִ״شڳٸڽظֵ״طԼԣˢΜ˙˙˛Ξ̟Ϟ̟ΟˠΜΗΙ˞Η̜Й̙ϗΗϒ̞˘ϛ͞СΝ̟ΠϤϡϡϠ͝ΣФϡͣЛͣΡ̣ѥѠˣФΥѤΤЧϤͧФΪҪҪҧӮҮѭҮЮհԮӪԨңԡӟӡҩӢҢԟԧӦӤӪרӦӤӤӦӣԤ֟ԣՠўѝԛӣؤآӡՠ՚ՙԢ֟Ӡ֡פמ؜מ՝֠ԡ՜Ԟ֛֝֝՛Ӟ֜՞֝ԝ؞֝ם؟՛֙ӜԞ֣؜ءؠ؜֚֠ל֥خټܾة׭۱ۺܺ߾۬٪رٶٵۻܮب٧٬۫٪٪ث٩تخڴٺܾ޿ݼ޺߻ݺݷ۷޼߿߳۶ٳڼۼܻۻۻܷ۴ۯٯڮڰٮ٫٩٬ۯڪجخۯۯٮذ׭جׯڱܰ׳سصٸػܶ۷ֻܼܽܿۿٽڽٺۼ޺ݴ޶غܿ߼޿ݿݻݽܻܺܶعݻ޹޼ܻۺ۶ڵڳܮۮ۬ۮحٮ٬٨׫ۯڮٯ׬׭ڪ׮خ۪۩خݮگج֪حש٬٬دحخ֮ةثۧ׮خح׬ت֪֪֫بة׬٧ةث֫بجح׫ج۩حת֩׭ج׫ةت٬էժ֬ثثשثإج֩Ҫ֬׬֪ת֭٩׬تԬ׫֩اթتکժӫ֪֬֩Ԧת֪٤ԪӪӭײԱٰررٰ׮֫دزֱص۶طڹر״׵رٱַطۺغڷٺٷٵعۺٹٸػص׶׷̻ԡ̞͠ϞΙ̛͢ѥџ̖ΟҘΚ͚̕̚ΗΔЎΒҘϚӖЗ͗ϗњҡҤЦѣӝ͝ѡϠРѡϣϢϠНͥѡϢѢϟΥѠϤӧңФѢΪѪЬϬΪѱԭ׮ӰӱմӮ֪֭֨եӧգԥԦգԥӤӣөӧӡөԨԦ֨ԦԦզ֣؜ԡӞؠ֜ן֣՜ן֤םכנםӡ֝؜՜؞ם֝טכ֜؟֝؞֣֙֜ל֛֛֝נ֙֜ן֝՜ԛךךט֝מ֞֝؞ס؝ئ۷޿بئڞ٣שڰڴޤئئ۪۱۪߱߱֩ۤڤצ٬ٮۮڮ٬ڮ۴ٺۿݽݻ޸۳ݲ޷޷߮ܮݶ۶޸ܻ޽ܿݺܸݳڳٮ۫ڬٰد۲۰ٰܰرֱٳڴܳصزٷٲشܱڵڷطۺٷ۹ݽؽػ۾۾޾ٽٿؿ߾޺ܶݹݻݺ߼ۻݺݾݿݻܺݽݻݶܶݸݸ۷۶۷޲ݴޱܱگڱܮۭ٨۬۫ڪٮڮذ٬׭گۮۮٯخۯجڮڪۮٮګ٭دݮٮۮخ٪۩د٬٪حڮܪ۪ګڭد׬ثثت׬ڬ٩٪تثت٫ܩ٫جת׫تתثث֮ٯګڮת٪حاثجحت֮ت֭֬Ԧ֨ث٨׫حתӭ֬ש׮جծԱخ֪Ӫجب֦֫ةڰְٮմر׬ֱ٭ش۵ڵسںٻعܻټںۻ׹ظֻعغ۶ٺٻ׺ؼڼٻַػټڻؽٸм՞˟Л͡ОП̣ΡϡϢ͝Μ͝Ι̠іΓҌ΍ΑΑϒѓҐ͖Ύ̖͞͞ϞϠ͢Π̠ϢП΢̞ϝ΢ҡΡМϢѢѡРСѥЧѥЦѤΦҦѮӬӭүӯ֮֯ӯӲذӮֲ֮֯ԦӤӣѣӢҢӢӢҢџћѤԢԝ֢գӞӤ؞֚әѝӝԜӞ֠ל՘Ӛ՟աלԛ؞ؠם؞עؠ֚ՙ֜ՙ֛ә֙ԛԛ֡כ؞֞Ԛ֘؝ؙ՜ח֛ם֙֘֙֗Ԙ؝ךӛӤ؝آ׫ٻ޿ݱݪڥ֥֠עٞئ۩۵ݪ۪۬ؤأפԥؤڠۤأ؟֦תܱڳڮڮݯڴۺܼݶݭۭ۱ںޮڪܪ۱ܶ޻߽ܺۼܶݹܱذج۪٪ثײڵڷٶض۳ص۷۵۷ڸؽڷڸٸٵ۸ۻܽݻۻٽջٻܻٽڽ߾߿޺ݴܵٳܻܶܶݻݺݼݼݻݼۼڶݶ޹޶۳޴޵߲ܱݮۯܭٮجٮڬ٪ٱܱۭ٫ث׭ׯ۫ت٫٩ةڬ۬تجګ٬دتجڪۧحڭ٬ذحح٫ۭتجحګת֬تاب٬׬ج׫׭٫٫ڬ٪֩׬ح۫׫תٰ֪֫Ӯ֪֫ծ֬ٯװٮٱح֨ت֭تխح׮֪Өפת׭ج֮د֪ԭլ֪ӭӧӭԪبԬԬӪ֦׭ի֭֭ثحկدӱֳضܵ۹ۻ׶ػغع׺ٷػؽػ۶ڹٻն׹غ۸ڻٺջٻٸڸ׺ظֻϿҡ˛ˢʙˢΟ̟͠ϡΘΟ̠͖͖̏̚͜ϗΐ̍˕ϕГΖΐ̓̔͜ϙɜ˝̛̜̟͝Δ˜ș͠ʡ͛ˣ̢ΠΟΟ̞̤Τ˥Τ˪̤ͤϨΪҨΩЪѱұѴӮկӯӮ֯ӫЪӭӦѠТϜќϘМΣџѝџӜџԟҠҡҤӡӖњњќқҘѝӝӠќԘӜלҜ֘ћўՠ֝ӜԟӗҙҙӘҘљӘҚӝӛԚҙҙӝלӗҜӠ՝ԑѓҙ؝Ԟ֘՚Ә֛ӟӞ՞Ԥتٹݹ۳ڱܲݲܱ۬ٞץ֤آ֠ף֣؞ױ۾ߺ߰٩۩٧تا׮۫ۤؠץإ֣Ԡ֤֤֦֡خرٴ֭֯ױٶܺۼ߽ޱ۰ݲݴ޽߽ݼ߽ۯزشٶݾ۶۱ܯۭܩڬۮٱڱۻڽۿ۽ڽٹ۷عٵڱڱ۲زױضسش׶ضعٻغظغ׸ظٺܼڼڽվڻػػؼؾۿٿ۾ٿݿݼݺݽݼܻܸ۶۵۵۳ۺظ۷ڶݷػ۹۶ظط۶۶ܶ۳޲۰ۮختװٮٮڪ٭ڬ٬֮׬׬دײحخحت֭ثجا׫ڪ٬ة֪תתר֭ת׬ثة֪֪֭֩թثٰ֪׫׫Ԫ֨խ֫תծ٪ث֩ԩժլث֬լ׭֪ۨխԫԬҫ֪֮֮ժժթӨӮ֧Ӫ׮֥ӮְҮԭѰ֮ծ֯֩ѫӫөҧЬѮЪѬЪϨЩҩѫѪԫҪҪҪѦЫӱӫѮӮҳձӳԲҴ׵ֻԻ׸׼ػӷشնӷҹӶնַԴӶҶӶкӷԷջ׻غطӸҹӵνԗ˔͓̐Η͓̗Ι̗̜ӝΤ̜˕͑̎ΑΗϒ͒͒ϑϓЍΏϐВДϔ˓̕˙ϙ̎˒͛Λ˜МΛΛϞ̟̞ϡϝФϡѣССΦͤѥѦҩѧҨѪѨҭԮԩӭѫӭӪԬӣѠѡϡѥӣҜЛјьϓҘҖЙәԞӕіэԒӐӘӚӚӛՖӖԜԛט՝ӚӗԗӑՓғәӚ֗ՙӖԗՙ֛֗՘֘חԎԙҚ֗ӗԙי֙זәԘӚЕїӗ֛ט؜֟ќԔԜ֚Ӡءإة֢֢֞Ӣؤڦڡנ؟֤֝ؠ֜נڣ׳߾߱ޮۦ٤ףנԡ֣آڦٟ؞֚Ӣ՟֣ؤأ؟٨ڮڬڪ֧׬در۹޼߾޶ެۨڟخݶ޼ݸٽ޽߿޸ݲۻڭٱٳ۵޻߿߸ݻܱ۪ۥۤ٤ۦݫ۬ثٱ۶ۺڿ۽۶ڶٳٷڴٶ۶ٷڵٶڵٹٶٸٸ޻ۺؼںػٻݻܽܽٻڿھ۽ܿݾؿڿݼݼ޷۹޵ݺݶ۹ٳڱٮڳص۳ٳ۶ٷض۶ܱٳۮذزܳٷ۴زدر۱ݮ۰ۮڱ٭٭۫ڰ٭جܪ٭جخذج֫רۭ۬٭٭֪٩ثڪحڬ֪۫ج֬֬إڨܩ٩֮ت֪֥֥֪تڬ׬תګ֪֮֨٦ةت֫խԮ֨ը֪֪֭תԪӪҬѬШЭѧԥԨѫѬЪѪӦѪԫէөҧЮѪӬӪլҥԨ֪ѮЪЩΦѤЦѪҪҨͧϨΨΥΨХШѩѨͪΪѫ̩ϪҪӮӮѱҲѳӳطظ۶ֵٹѵѶӯӱԵرѲӳүϱзѯбԱҵӲմӴϲΰұŻ֒˖͖̕ΐ̈́Η̚ΌΒΔΙΚМϓΕΊΐ͑΋Бϐ̖јВϐ̏Α͔ΙИϗ̖ύ̐ΑЕДјњ̘͒О˝ЛПˠ̟͟Σ˝˞ͣˣѥϥѩΦͤ˦ҧЧШѦҨԩѣѦЦКњЛЛПҟΜϓύДΗЗҖҕӕӖДьғяԘӛؘ֖ӘАёюҒњךӗӛԗӖΔіђ՗є֜֙ԚӚԓ՗њלԝםӒԔӘҗԔ՗ӘҘӘԝ֑ԓ՘ӝ֗֘ԟ؜ՠ֒՗՝Ԙ֚למӟԞ؛ןס؝֢՟ա֤ט՚֜֟קڴݿ޸޵ݮۡڡؤأԧ٣ؤ֤ءؤ٠לأ֤آ֠؟ԟ֡تج٫֪ئ׫ذ۹ݼ߻ݴܫ٥بڮڲ޲ެݬݲ߶ݷܭ۪۪رڻ޲۪ٯ۵޴۳ܶݵܴ۳ۮ۫ڪܩ٤٩أؠڤ۩ڱ۵޽ܽݿۿ޾ݶݵضױصڶ۹ٸڷٹٹٹؼؿۼۼڽٿݻ޼޾ݿܽڷܳگܯܳڳֶصܳճֲرַشڷ۷ڶرܬ۲ڱۯدܳشڱڲۯڭۭݮڬ۴ܱݰܱحڮڮٲ۰خٲٲذׯۮٯ٭׬٪٪ت٧ڭګڪ׮ר֭ج֪שע֨תحخ֭֬֨تԫثاש֫د֮׫Ԫ֪ԩԪԬ֩թխ֮֫ԫϫөѨѪӨӬϨѩ̤ϤΨΩѮЧЪ͢ΤѩѧѦ̩άͨѬΧΪ̪ЦѬͨϤѥ̡̧ͣͥͤͥͤϨ̢̥̣Τˠˡ˩ͧΣͫɨ̢ȯ˧ͬͧбӸѶִշԱӯկԳӲҲаή˫ϬΨΦϫˬϯѰаͮͮίαҰбѱԍ͒̏ѓΑϚіΕʑΌ͕ϓББΐΊ̊΋ω̎ώΌӈΔғώ͑̐Β̎̊̓ъБ̏ύЏΊВΐѕњЛϡΕіΛȠϠΞѡΦϝΟΞΝУТФѧΡͦѤѧҦҢѧѢѝЙЗДϒϖӐђіЏΏяяюяЎҐҒѓюԘӒӖӓӔѐҚԘҏВӎԙӛ՚՛ӒӗӖӛӘіѕёѕҚԙךҚҙљԒԓԖӘԕӕՙ֜Ҕ՗֐ӗ֚֚֓כԖ֑י֚֞ԝ֚՝֛֖՘ՙԜ֚֞֞؜מԠ֝ך՛֛՚՝֣֞ףذݶݭڳܷ޹߹޹ܪ٩٨ڧئ؟֞֡ןڛ٤ל؝Ӥפ٢֢֧֜֙֡֡ؠף؞أקإاٱظںݽޫؤۦڤڪکڤٟڧکާ٤עائڭ۷޼ݸݫۦ۬ثڭۨڰ߭ۤקةڦ٧٥ڥڦڥեۧڬح۵޺ݽ޽ݼ۶ܰڳٵ۸ضڸغطԹ۹ܹۼٿڽ߽ݾۿܼܾݿܿ޿߻ݹݷڴ״ٳׯذֱزҰֱرشض׹ֶڹܶ׶زۮشۮ۴٫۬ױ׭ݫݫܭڰ٫ثتۯٴڰڰخجٮدٮۯڮگ֭ذٮةج٪کثת٭۬۫٫ڪذثت٪تԦ٪׬ת֪թ֪תש٬ح֮ժ֭֯խӫ֬֫ծԪ֧ը֭خիөѬҨΤ˦̨ͦΨ̤ʥ̨Τ̤ͧˣΣ̦̤ͤΤˣˡˤƠɡˤ˦˪͢ˣ̣ɣʥ̥ͣ˥˟ǠˡʟɡʞțɠǜĜǞǟɝƠ˝Ǣ˦ƪˤϪΧ̪ͧέήұҰίϯΫάήΫ˥ɥȥƣɡƣʦʩͪͯͭ˩ȭʯͯ˱̱ȾӚ͑̎ˍ˓ϓБΐϐώ̓Џ̍˓Ό̍͋ψ̇ˍ΍͊΍΍Β͎͏ύ΍͍͐Η̋̎΍ύϋː͎͏͒ΔΒЕїҖ̜˙ə̛˚̝ΞТʟΚΝ̣ͨѦѧѥҦѣΛӜЗіϔЗьҋє͏ьϊЌВяђӖҌғόϓҍѓђӕӗϗђБΎΏѓѐііѓҏїԑҜԙҕӜЛјԗԍАѕЖҚӛҔӖԐҗӓґѕՕԘӗՑіҒӖԕ֚ԛԝךՕӘӏՙԓӚԛ֜Ԙӗӝ֚֙ל؟՚ա֝՜՗՘֝ԛ՜֠ס؝՞ؠٝן֥֨סףעآף֝֜֟סףؘؠٜؤؤנ֢֝ם֚֙؞ס՚מ֜֟֝ננԟפףثجزڼ޿ޮئؠؠ۠ڤ٢֤֡ՠؤؤؤأب۞إث۶ۻݹ߳ݧۦ٨שب٩ڬػުۧڨ۠ؤ֥آשٜנףפ۪ۨ٨رعڽ߻߶۷۶ۭڮخ۱ظۻغܿھۻڽٽܾۼ׻ٻ۹ܼ޶۶ڵׯ׳ֱرճز״ֱٳֱԱִض׻ٶַٵڴررزٲׯڰ֬׮خ۪دجث٬٬خگׯ׮٭׮ذتիث׮ׯحڮح٨ة٩׫٬٪ڮٮبجլԫ׫֬׫שת۩֪֫֩Ӫ׫خװڮ֮ر֪ԫԬԬԬӬԥӭӬӥҩЬҫЩΨЪЩ̨̣ʧƨɤ̧˧̩ʥˣˣǪǪʧˢʠˣɢɜȤšǞƛǤɤʢɤˢʢɤ̤ʡ̡͞ȞȝǛƖÛÛėĞǗݛřĞĠơŝãȥɧɤʡơˤʥ̩̪ͦϥͨˤɪǣˢŞţɤ̤ȣȤɥɣɧʧ̬ΨͭˮɮɯŽ֒ˑ̖̉͒Θ΍̌ΐ·̌΋ϗϒ͍̋͋}ΉΉˍΐ͍̓͐Άόӊ΋΋щ͒БЌ͌ψ̋̍ώ͍ϋ͍̊͑Ό̑ΙϚˏ˖͖͗͗ΚΛћќ̝ϡХӡͣҤϞќђΎώАЕѐώЉыГЏ͊ЋЋҎьёҐҕґѓьЎюЌӐԔӐΕњёБӌљ֓ՌΔҖӓӖӖәՖӕљѕГяӖԑі՘՘ҚҖ֕ғԓґԘؙ֕іԔԘԖדҙӛ֚՚ӔՓӜўӚؙ֖ٜ՗әԝ֛֛נڟ؜ՠםԚ֜֘Ԛכוՙיӣ՟֚֝ҟ؞ךנכ֝Ԟ՜֚ӝ֜מ֟ٞԞ؜מכ֞֗؝ן֞֟ך֚֝آؚמטמ֗՝֚֞ס֪ٸ߾޿ުۣء؞ٟڟפ١פؤ٥ئנ֢נ؛ؤפخڳ۹ݬ۞ڣܦڤ֤ؠآ֯ٸ޷ݩ٥٣ڤؠ٤צסק٠ؠ֣ء٪تتڰٻݷ޹ߺ۴ڰۨڪתٶٸۻڼڿ߽ܿھ޽ݻطڸݼ۽޼߹ݵݶܱׯ֮֬Գײزֳ׵ֲԯֳַ׷׶ֶٺֻظٲ۳ر۳ۮز۲خجܮٯڭحխدڶٳڵذ֮ذڮ׮ٮح׬׮֩׫ثة֪٬ڪتկ٬تث֨ڨح֭֬خ֪֩դبب׬ժ֮׮׬֭֭٬ըӬҬЪҬάѫӪӭӬӭժթͫЪ̫Щͩͧʣ̩ʢɝ̥ǦˤɡˢˣˤɤɡǡȟƣǣɡǛǛƞ ǞƠǚɟȞɞȠęŚƞĘŝĜƙÕÙśƙÞƞěĝğƢǟˢǞʡɝƣʣŦǠǛÞƚߍȣŢâåȧȨɨɨʧʦɬý֍͖΍ЊΒ΋ЌΒΉΊψ΄̈͑ВΒ·͇Ό͊΀̉ϋϏΎΌ͈Ɉ̊όЉϐЇόΉˍ΋͋Ќ͌хЋЊόφΊΉˇʐёҌΎώ̎ыҎѕЎΘϖјΔБыьЈЉЌЈώБь͈ΌӅЋАЋ͕юяЎяҔӍЌҍӏӑђҋюԓӐҙ֚ґҌҏъюьԋҗИӔјьӓՖ֔טӜ՘ԖЖИՖӖԒזӒҘԒӒԏ՛ԋӗՍҜ֕ӑҋԋӏԌ՗ԘӖԙӑ֒ח֗Ӛ֜֙Ԟ՛ؗӘ՜ט՚ؚ֙֙՛Ԛ֖֓Փ؝ٛ֞םך՗֚י؛לכӗӕԗ՜֚֚ԛו՜ך֑֚֘֔ח֙ךآڜ؞֙כٛךؘל֚םך՘أݮݳݶݭ۴߹߹߸ݪܣڝؘٟٝٞ؟١֞ژ؝ۢ؜ؤؠמ֣֜ן֤تۤآءآ؞סם١ۥ۫ڮ۳ݴڴݶ۫ڢؠآץעٟءڤأأ؞֝؞ۤ٠ئڬۮگ۲ڮڮڦبۤװشں۽ݽܾ޺ݸۻݿ߿޼ۻ߽޸ܵݴ۫ڮݯخگղ֮׮׮Բ۲ٱױӵԵԵֱضٷطظ״ְڲخدٰ٪ذڲثٯۮ۰ۭخۭ۰ٯد׬ڮذخٮ׮ثة֪קקإ٦ר׫שجرڮخخ׫֧֪ح׬ت֨ئ֧֤ԣէ֨٩֫Ҫը֧ӫԩիҫΨͪΩͪҦΪѪѨΦͥʩ˨˨Χͧͧˤ̥ʡɤɥɤʡ̢ȡƟƟǟƠǝšʟȢǟÛȚǗȖƛ›—ÙėřĔҗΑ”٘ؗÚÚƟƜƜÞƛĝśƠɚȟǟĥĠǥǥơƠʧՒ˒͑̓΀ː̇ɍˇ͒̍ɋ·͐̂̊͐͊ˊˈʄ͌ɉ̎ʋ̊̏˄ʆˋ˅̆ˎΉˌˇ͇̍Ɋ̉̊̐ώύΆˍʌˇ˕ύˊ̌Ɋ͊̍Ύ͍̋φΎЋΉ͋͌̍ώΌЋ΋ЎύˎΌΌϋяЎΏϒЍВЍЎЏЉЎБҍіϕ΋ΒΎΔΗӓΒΔ͔яёёьϑґѕΙєљќҔљҚӕӗϛѐΖЕћԛӔїёИәҗѕјӘҕӍΖӗҒϖҘәѕԙіϔϒМђљ՜Ԙ֘՛ԚӝӜ՚ӖӘӗ՟֚ԘԖӘҘқӚ՟ԘӕҝӞ՘ԝӗ՚֛֚֗ӗ՛ӖӕӗԘԘ֖ӚӞԗӗҘӚӘ֞֜֙֜ՠՓӗԙ֘נל֝ӥ՞עԧ֦֧ڦةإ֫ڣ٤؝؞֠נգ՞֛֛֛֞աՙממע՞Ԟע֤֢؜֞ע֤֞ל֢֣֤֜؞إפ֤ءب٣؝գئפؠס՛أءפ֡؟؛؟֣֣֠ءעةجحץӦֵֶ֪عڹݾݿ۹ٸؽڽػݾݿ۽ܹݽݾܽپݿ޳ݶܱڳدׯذدׯԭױկԱֲҴӳԴմոַӷָշ׻Ըصڶ۵ٰصֶشֳָخرگخرյձױֳյٮְֲխְ֯խկ֯իԫӭת֪ժשծ׳شٯٶԮӭլԪԮ֭өլ֪ӭӪӪӨӬجӭӫԯӮӪΩΩϩЫѧ˨̧ΩϫΫͩʨ̤ɬɩʧ̪ɦ˩ƫȨ̥ɨŨɤƠ Šààâȟ ǣáÞàÜśÙ“ŝךÚÝšěǤáԓˏ̗͐ʏˍ͋͋͊͌Έ͎ˋˌ͊̇ˍ̈ΏΌ̊Ɏ͈̊̊͌̍͆͆̆ˇ̋̊̍ˎϋ΍͉͋ʍ͎ˎ̋͑͊Ό̑̋ˏЄ̊ˋΆ̋ЌѓΔΌɋˈ͊ϑώэΑΎ΅͉͋̅ЉЍόΒЏΏΐ͎̒ЍЏӍύ͆΋̎΍эҍѓБї͍іКВΝВїѕҖΑіӐҙҙљњџғМԗҘИҚҙԛԘќѝҔИ՘ЗґԖ՗ђҘњϕэҘїӕӑӗјԔјԙԖӜחӛә֜Ԝ֖֠֜֘՝ՔԘԝ՛ԗ՛כ՟՟Ԛӝ֚՝֘ԙԞךҚԘԕ֕֜ӚәӚԝ֟՜֘֕՚՘ҝלӝ֒ћ֘Ԟ֘ӓ֕՛Ֆәաל՘Ԛ՛ԕә֚֝֠՚Ԟ؜֟֞ןנ؝؟ؤ֟ם؞֢֝֙֡Ԝٝ֞נט֡נژ֞ןբל֠٤ئ١֣֢֛֦֛֟֡إפآբ֞أՠ֡֝מ֧סכ֤֤֢֡آئ؝ؤأע؟ؘפפ֥֪֠ײػٻ۾޿ݻ۷۹ػڽݼݽܽػ޽۹߼ܱܵګ٫׬رذֱ׮ֲճױֵ֯կԲгѶԶӻֹ׸׽ںؼ׸ضصֶسڳ׵ٹٷ׺ضصٳڶٶڱصնӵֱֵӳӴװׯֱֳղԭ֮֬֬׮׮ث֫կֱذֱرس֭Ԭ԰Ԯ֭حӪج֭֯խծԬխӫӭӪծӬϩΫϨѩͩȨĄ̇ͪͮΨ˦̧ʧȦɤɦʨȩ˩˧ǧ˥˦ɢǧäǧơǜţàƢɢǡâģà›ÛśĘÛߘÝţơơԒʐΒ̋̎͐͏̅̉Ί΍Ίω͎̋ˌʉϏ΍͊̉͐ˁːΑ·͉͇̆̌͊ˊˋ̋͌΋ͅˊˌʄˋ͉̊΍ϊˌˉˋ̉ˍΊ΍ʆʅ͎ˎʇɍ̉Όцˌˈ̌̌·̉΋Ύχό̍̎ϏЍюхϊ͋ΐω΍ύ΋Ή΍΋ђюБӐїӗњҞӑϚ҉ώіѐюёӏњЛҞԛ֜ҜјҘҘϗқӝҞџѣњԔԗӗҝӖҖӗѐђђԒњӑғҘӖ֛ӖՙӕљҘՔ֙Ԛә֕ՙ֖ӞԚЖљ՗՚՚ԛԘԙӗӚԙӚ՘֘ԒәӗӜԘԒәՖӘӖ՚ՙҚ֙՗՛֛ؖՙӖԙ֚ԝ֚֘֙Ԛ՛ԕҕՖՖ՚֕֜יәՖ՛ԛԝ֛֗֜֞՚֔֜֝՚֜ژ؝֤֜טט՝֞ל֝֝؛֝֙מӜ֜ؗ֙ՠ؟әנן١םؠ؞՜ף֢ؠؠנסע؜՝՞ԝ֚ננ֡פ֤إؤؚڠמ؟ؠ؛מ֢֣֡ף֣ԟ֧կ׻ؼܾܾ޾ݻݷۻܶݶٸ۽ٻܻط۹ܶ۶ۻٺܴٺܻ޹۵ݵ۱ܯ׮ذ׮װسֲԯְֳԲֱүӱӱյ״صԸԵմնصֺظ׸ضٵ۷ܶضٻֻػض׶غٶֳձӮӲֱճְճӯְ״հ԰ԯְְ֮Ӱկ֪֭׬װױ֮׳ֱׯ֮ԫ֭Ӭԯ԰ҮӪӪӭѫЭӬ֮լӪӮիձҪЬάΩȨǤɦȦʢ˥̧̡ʫŪǣʪɪȩʣʧɪʩˤɩʣǪâɛȟśǞƝǠģŞǟǞĝŜž×ØØ“’šĜ֎ˎˌʌĉʋ͒όЉΈʄ̊ʐʅˌˎ̋Ή̉ˈ̎̊ˍ΍͍͎̌ˍʊɌɇː̊Ɍɍˎˉʋˋˊ̍ˊˍ̍͒̕˘ʎɊˇʆ̋̎͆NJˊɊɈˌ͑˒ˊˍΏ̈΋͍̎͊̈͐ϓόώ͎̏Ћ̊ΈΊ͏ϐΑ͏ύω͈ύїЏЌϒьΊїіЏϐҕѕіӑђјϑҡѝѠќҜѝѝјҙџϞҜѝѠ՚љҘӕԛәјїєјЖҖӖ՚ϑΙҗёЗӘћӘӕјԗԘћћԕӕ֚՛֣՜ӕԖ՘ԖԗԚӖӛӓђҙӚӔԙ֛ӡӝїӚӛՙ֘Ֆ֒ӘҚӚӕՒӑ֕՛՚ԗ՚ԑӖҘԚ֜ԗәԛӚәҗԙ֙՚֛ӗԙԚԒՙՕ՜֚֝֟ԛҘԙ؝؛֚֜՜֟֟՞֙֞؞ם؝֟՟ԝ֚՛ӛ֛ؤ֛Ԣաנך՘חנףנ֢դԡբכԜמם՝՛֞ןՠԟ֡ןأ֢ءעՠ֛֞֝֟֡֡դ֤֧֥ױػ޷۰۸ݸݻ޺޸޿޼ݻݿݽٶغִֶرٶڶܹض׵ױڴضضֶַ׸״۳ֱذׯخجֳײիհԬկԯղѱԴӴճմָն׷׶չշֹ׹ֶ۶׳նոضպڷַ׼չ׵ֶٶӷӱѯӬѭӱҴӳӳҳӵӯӰа԰֮հԲհְֱӰӯկӱخױҰѪѪήӯҬѭϮӱҮѬѬѮӨӮҫձ԰ѭѮϫ̬˦̢ɡŠƦȤɩɧȨ˫˭ɩͫɩȥǪɬ̩Σ̩ɦǨŧšǣŢÝߢŝàÜÞĕ™›™ՋɐɊȌɍˊʊɇˉˊ̍̓ː˕͈̅ˇ͊̊͆ˉɎɆȍȈNJɇȋɏʐǎɎˆɍʌɌˎ͋ʋɍʐɏʒȒˑˌʖʎȒɋɋɎˌʊ̎ʍȆɉ̋͐ˎ͏ΉˍΊ·ˍ͕̋̎Ϗ͗͌ˍ͕̕ΌΆ˒̌͒ΑΘΗБΒϏΎϋΌˋΐь΍ΏΎ͍̌ΔΐϕЗЗΒЗӖΗџΡӟѤѤңҡԠѢСӞҝНўНџјИіћҕЙΙԙӛЛӟҠјћДϞџΙҘԘӗўҙ՞әԝ֗љ՛Ӝ՛ՙԗѕӖқҞ֘ՒҚҚӜәҘқӗӖӘҝԛ֒іҗїӕҙӚҚӘИїӚӚ֖֔דЛғәӚҒӚ՝՗ӑҘԙӛՕӚՙ՚Ӛӗќ՟Ԝԛ֟՛ԛԗԛӝ֘Ӟי֜֙Ә֞ա֝՗؝֚՟֢֟ա֞ՠ֛әա֤֞םԠ՟֝՝לԠןע֢՟֢ԡԞԝԝלםԢԠΤӟբԜӝ֝ؤ֢֝Ԧ֝Ӟ֤֟֜֞Ԭӯֱ׿۲دٮ۫ڭۧرػ޸޸ۼݼڽݼܿٶ׶չ׶ִԱֳֵض׶ӱ֯ԶӶ׶ԲյֵױֵӲձױղմԴֲԱ԰ճԲԯӰԱճԳԵԳӱԶչָֹٻֺֺֻ׻ַ׺ԸֶӺֻֽԺֳӰִԴԴѱѯαϰаήагԵֱҴҰҮԱկӯԯӱխӯβӮӮӭӮҮЪѭ̭ѮέΫϩήΫ̰ˮѯͬͮίѮӬԨҮ˫˭˥ʥĤţƥţʦũ˪ê«Ȫʩʪ̭˭ƭɪˬʩ̬ɦǤǡĦţÝş¤àş¤ÜÜğâԆɊˌΆˌˈɋˈʅ̅̇̄zɐʍˍˊ̆ˆ~̆̏̋ʆDžɋʌˌ˅ɍ͖̋̋̎˒ɍʎˍɐˏˑ̑˓˗ˉ̋ˍ̆ˌˉˈȈ͂ɋΆ̈̇ˎ΋ː̃ˎΎ̑Ύϊ̉Ή͋̑Ή͐͏Ќϐ̐ЈΌΊ͆Ή΋ϔόΐωψычЌϋ΄͋ьϊωψΊЍ΋ϑΓґЍΓҚҜՠѣХѡӟԡԢԢҢԡСԞϝҘЛҝԜәѕќӗқ՚֟ԛћӚӘӚћՓѕΖВӑӎѕӘўՓՔԟ՗ӛ֘ӗԒՙ֘ӓҘіҗҕԖՐӗӐԐіДϖәҞՒՙԒӚӘӖӑ՚֚ԛכ֗֓֗֗ӐӕӓӒӖԙӕљҘәӘӐҒԊ՘Օӛ֔Ӓԗ֕ՙ՛טҘ՗֜֘՘כؚ؜ӕԝԙԛԘ؛՜֟՚Ԗә֙֙Ә֗՘՘ӝ֢֛֞՛֛֘ՠ؛Ԛաؙ՘ՙ՛՚՚Ӝ՝֡؝הכ֛֙؞ם֚֚֝ח֢֚֜֙֝Ԟ֝֙՞֥ըخڱػ߬ݭڦڤ٧٤ؤ֤֮ݳݱܺߵݮڱٰگ۲ܺݿݿ۷ԳֶָرӯԱֲֳկԯֲִҰֵѱձְֵԴֱرֲ֮ׯճӵԲձԱձձհҲӲճӰӶҲӵֶӶֶֶԶշֺ׶ֵغնӳַַշطֱӭֲձհұұԯѰЮͫϭЫϧϫѫѬЬѪҦΫЩΨҩѨϫϩ̪ΫѨͤΦѨЦѥ˪̪̪ͨͪάάЭѬӮͭѭҬͫͯͪͧͤʡɟĤƥǡĢšǠɦɦʨ̤ʧʧɡʢɥǦǦȪʢǡǠɢÞʞǜšĚۙ–šĞŝĞ֌ˋˋ͈ˈˉljˊ̏΀̌˃ɐˎ̇̈ʌˆ̊ʉ͆ˊ̌́ɌʎʎʋʇčɊȒʒʖ̖ʒɍɕȑȑ˔ɏȌˏˋ̒̉ɑˍʍˑΊ͋̑τɍːː̆˂ΎЋ͋̓ʍΌ̉̌ύ͉΄ωˏ΋͈ˊ·Ўώ͌̒Ό͌ˍ͉ωΑώό͎͍͐͐ϐύϊόύ͎Γ΋ΗВϘџԙќРУѣѨҢѧ֢עѤѢўϛНҜϜԞӜӚИΗјѝљԠԢԞԠѠќӖҕӚЗ֗ԘњћӘҘЖђԚ֒әԛҘҙӘԓә֜ԝՓӖӖҙӚёҕҖԕӗїҖіӕ֐ґӐՙәӚԞ֕әҗӗԘՔӚ՜Ҕӑӛ֑Փ֘ՕӖӘԙҖӗәԓҘ՚Ҙҙԗ՘ԚՙԘӛ֗Ӡ՜Ԙՙ֝֜ؖ՛ז֚՛֛֖֚֜ӗ՘֝ӛ֘Ցәؚ֔؜֜ӟՙԛ՟֛ԛ֕Ԙԝ֜֝Ԛӝן֝֜ա֝֞֞ՕՖל֣֡՝םԛ֛ד՛֛֟՛՜ץըծزطֻؽިؤآ֣ٞע؞֤֡إ֫ڮ׬֭ؤئتتٱ۹ݿ߿ۺظ׺۴ֱֱֲֶӮӲղկְҳԶӭմճ԰ѮүԱճֲزճԵԶնִԮӰկԬұѱүѲѲԱҳѱֱյԵӷӴԶӷطշָӶҹԴҶӲѲԱҮѭѬΫʪ̧̦˨͢ˤͪ˩ɥ˧ʥɠʡ̣ˤͥʡˣʟʢɟ̜˛˥ʤƧǧȠɠʥ˧ʨʪʦʩɪ˭ͫЭϬҭէͨ˪̩ɥȠɡǚƞǡƞğߊǞǧɤɤǣɦáţǠɤɪɦǤŤƛǠÞėÑƔ¡Ĥ׈ʖ̐Αˎ̋ʌɃ́̉Ά̊Ɍʈʀ̆ː̈́́˄͆ˎˋʑ˂ɉʌ̑ːʒNJȌɐɎ˗ɐɋǕɎɖʐɊǑˑː̎ΐˏȉˊʋ̊ˆʏʊːʋɎˍ͓Ε˒̒Α̋̌ΐΎ΋΍ϋ΍ΐΕЇ̉̈͆ͅ·͊ΌΎ͍ώ͈ΉΐюэЎΉЍьΎЌ΍΍ϑЍь̍ΚӖКҠѣϥЦӤϢѥҥӤңҦТѥҠҡҠϜѡԢҟқѠҠҡӠӡӣћѝӖНՔәӛә՚ӚҢԝբԝћӘӘ֙֗՚ӛ֗ԙ՗ҙӔәҗӝՖӛӘёҒәӏӒԔԙӛїӖӓӘБҘәӗӕӓДђԑӖԜ֚ӗҘҗӅ̗ԕ՘Ӛ֘ԘҙӕӔԖԙՖԗԖԖѕӘӖԘ՘՚՚՜֖֖ӗ֑Ԙԙ֗ט֛֟֞֜Ԛՙ֛ט֘מԓӛӛ֚ӛ֙ՙՙ֝՚ӗԘԖӘ՚՚֝՘әԚԙӝ՝י֝؜֡Ԛؙ֙֘֝֟֝֡֞֗Ӝל֢֞֘أծ״׹ظ߻ܮݤآڨ֣֤ؤפ֥Ԥ֝؞ڥإפ؞ס֦֡ױܷݹݾۻݴٷٶٴհճϳնձӲҶҰӲԱұնӱϱմԵӳճմױ׳شӶִֶַӰӭӬѱҰѰұӲаѮѮӱԱֶֶֶҶճӶֶӱѱӰӲӮѲҮӬϪ̧̥̤ˢȢǡƢȞțɚǜɢȡȟǛŗƘșƜŚƞŞĚǟǚ™›ɛƚƟęřÛŝȢȢɧɪΫ˪ɣ̪ʫѧˢˢˡʦƞŜÞǓęÛğşĞĞƙĚĞƙşǟãŞǚǙŢơȠƞßڗěġ£ĥǥťȨĨƧ׏ʔ͎ˊ˒ˎΌʍ̎̊˅̋ˋ́ˁ͆˅ʊˋˆˊ̀ˊ̌˄ʋʈɎ̈ˑʏʎʔɍˋˑːɎˎ˓ʒʑ˕Ȗˑˌːˎˏ̏ˍ͋ɉˊ͓̎̎̎̕ˌΎΌΊ̍͐Έΐ̌͌͌Ό̌Έ͈͆ύҊϊϊ͆ψ΅χχ΋͇Ίϐ͑Ѕ͋ΖЈτБϋЌ̍ъЊшӔіҖΘϡҠФѢШѩѪԧӤѠѤФҢӣԤҞӘќНԟҜѡѢԣ֠֝ӝћјӚӔНМўїӚџԜҜϜ՛ԛԚӛ՛ԙיКәіӚԔә՘ӗґӘӕҗԖӖёӕӔєҘӏӗ֕ԎӔьґҎӚ֑Ԛ֓ғҖՏӖӕ՘ԙՙՙՍҗӖАԗՒ՗֙֘җӓӗ՛ӔҕՔ՚֒ҔԗԙԔӖՖ֕֙ט֘֙ӗӗؘ֘֕֗ՙӚזזӘ֖֞֔ԗ՚ԝ؛֖Ӛ֛՛ח֝ם՗֔ՙԟԟ֞֗֝Ԝ֖֙ԝ֞ӜԜ؜֚՚֚ט՚؜ؘؘ֙ס՜֣֞դ֩ڱعݻ۽޴ۡڤ؟פءأۡؤ֢آ՞֡֠נ֦ؤأ٥حٲۮ۰۵ݸ߼ݿ߿߿ܺ۷۷۷׵ٵձֱյӲӲԵѯԳӵ׮ԲֱѱհԷյֲֶ׶ӷ׶ִյִԵֲӱӫҮѯЮѯЫѪЭѪϰΪααұԯѯӮѲӱҭѪЬҨЪΧΥȢ͟ʜʟȢàƝțǖØśęĘŞǖďҏĚř––Ɨ×ÓơơǡǟʠˤǛǞǜɛşŘř×ĘڟĜşĚ™Ě؝ÛƖǚđžƞĠĢŤƥŦŪʨʭɪ֊ljNjˆȌɊ̊|ɁƀɁɋˊLJɅʅɆʍNJɋȇɀLJɆɈʆʈɆɈȋȊLjƂȆƈDžǑȉŏǎɒˌɐʑ˖ȕəȌɏǍɌɋljɉʋȈˉˈɆˎˊʋ̇Ɋʉˏ͇̈́̋͊̊͊̂̈̅̋̆̍̊Έˌ΅͂̋̅ˌ͂͌̋΍ͅ˅̊ͅʌϒ͍̉·˄ωΉ̋ϘΙ͙УϝџΤЦϢϡͣџ͚͟ϛΘϘΖϓΖ͘Ϙњқϙ͛љјњЗюБВЙΑΙΝњ͝ћԕҙΚҔӖҚՙљԔҔҕёЕЖΗϖҗєБ̕ГΒ̖іБҒΏ͏ΗΓѐғђӖԑΕӗҚґϑєҗӓ֓ҊΑΓЍΓАяюΊϓҘёϔїЗӖғҖѕїҔґӖҚԙӕϔҖәՙԙӛӗ֚ԗҕєҙҕՙԝԖ֌ӗљѕԘҖқל֚֜՗ӛәҔҙәԘӘӒӕӝӘӛіԛՙԕӕӖӖӚ֚֗՜қӘ՗ՖіқәԚӝ՛֕Ԟՙӥմضعۻݿݹ۲ۮؤ֝ԝ՟՟Ԣ֛֡՞Ӛӟԡԡ֤ե֠ӣةׯײ٦פժدٸ۽޿۾۽ۻٻٵظԶ״հӱԱֵղѭϯѱӳѶԷӴѲѶвѳӶѶӴҹӳԶմҵӲհӳӯӯЪί̮̫̫ͬɫ̬ɫˢ˪̫Ǫ˭Χ̭Ѫ˪Χͥ˥̢ɨˢʟƞƝǚĘƘÔӇ—˜â¦¤ǥȦʥȩǫȪʬהnjɓ̋ȏˇʉɎ̉ˊ̌ˍɌʒˊʋʆʍˎˍȊɋˎ̉ʋˍʌɉɋȈʓːɇǎʑǏɎɏɕʍ̒ɒɕ˓͑Γ˚ʒʒǏˏ̍̉ʉ̊̐ˉˍ̎΋ˎ̋ˌɋʊɊʁʉ̇ˀʉ͋Έ·Ɉ͆΂͂}͉·ΌΊ̉̈̌͆̋ͅ΍ыό΄˃̄͋ΊψόΆ΋Ћ̒ΑΙΑΗѠОΧѢѠТјқϜѕЕ͗ϒЎ͍͗ЙҚјӟљϘϗѓҒϋъїΔϘΙϘіЙДћјӕΜБӕԘїԗӋύьΔьώҐґӔӔјЖϒВЏѓѐҔӑҒϕБғӕԘёјҔӋѐΑњіӓה՗ҐђђђҎϋϔӔҒїґіҔϖВӘӔӗϛҗЎӖәӖӘԙӗқ֙Ӗәԓ֙֗՗Ԝїҗ֙њՔӗ֙՚ԛӘ՜ԕؔ֘֙՛֚ҔԐҖҙՔӛӖӚӘӘҙԗԘӕԙӘ՚ӛԚӗԗԗԞ՛֘יӜԚԙԚқԛ֚՛֛ՠֲػڻڻڹۮ٩֩٪ؤן՝؜֟ӠԠ՟؞Ԝ֚ע֣֢Ԧ֢עԤ֪س۶ܱب٨֩ڱܶ۾ݿ߿޽޹ܺٹظ۷ٶشֱӴֳӵӱӬӲҳկֱַٶֶַղղճԲյҶնִպնյӲղҰұҭϯаϪϫ̫ͫͪɤͦͪ˪̧ͭ˥̢ΧΣˣʧǠɞʝƚǖƙŒÚ˜ŒÒÚÙØÛÛäũåäɥèǨƦƬǬƬʫ˰̱ʯˬՔÑȓʌɐɓǚ̕Ɍȍʖ̔ʓː˚̌ˏȐȒȏɏȖɌǍʊʊȋNJȑː˖̔ɏɍȎʑʑʗǒ˒˒ʖɕț̠˕ɘɗNjɑȑˎˉǎ̐ˊɌ̐ɋ̌ˊɌ˅˂ȃ~ʅ˅Ȁʂ˄˂ˁˁ̀˃˂˃ˇ̂̅}́΃̌̍̄́~͇̄Ά·̌͆ͅˀ΄͂ΊЌ͍̇̍͋̈́ϒΓΗМΜΚЙГ΋͏Ίчφ͉ˋГΒэѓёϏЍЇΆ΍ͅЋЋ͋эωΌ͖ΑАђЏГҏыїӏВЊύ΅щЌЋΌ΍̎БΎґϔӊёϒАϑЅΏϑԐΖҏђЖӆюώѕӔӓяΐ̆˄Lj̋΋͘ГїёёғӑѐҎҎЍЉϒҖғѓӑԖДҖҕӔӏјՕ֘֕Ӛӛ֘ә՗ӗӘӘҗӏјӖҔјӔҕ֓ѕәԔӖԖҘԓԚӗӓӖӘӖіԓәԕӕҕӚӔъѓҗӚ֗ՙԖՕԔӗԘ֚ԗԚ՗ԒӗәՓӘӗӖөصۺطںۿ߾ݼ߲ئ՘֝՝ם՜՚Ԝ֢՟Ԛס֜ԛ՟֝ա֢֢ן՜֢֢֯ٱܱڨתإثسڹۼ޼߼ݽ޾ܽݽݺݹ۶۶۶۴ׯӴԵҲҴѵճֳֳҶԸԶҲֲֵյӴбӵֶҲҴӵӶԵջշӷӵұӭѭέϮΫͫΧ˪̢̣˥ˤɟȢʞǤʟǣǛȡɞƞǟÝė“ƑőÔӔԟŸĤãÝȧˮ˩ɭ˫Ǭǭʳ̱̱̲ͯϲ͵ͰٔɝȘ˛ʙəʖʖʟə˟Ρ˖˗ɔɖ̒ʒɖˍȖȖȐǏǖʒɓƘɓɕ˙˘˖˓ʓʚ˖ʖʌɌʗ͛˟ɡ˜̛Й̙ʔɑɋ̎̋ǍʐȐˎ̓̊˅ˊˁzȊɈ˂ʆ΅̀˂~{ʅ̄ɀ~̂̀~̆˂̅̇ʉ΁̇̆́̇Ά̆·́΅Ί·͂͂ͅʆρ̇΄ѐΊ͋ˇ͍ΒΑϗїѓΐЏΉ΅͋ΉшАϊ͉Ώ͎ΑЏБІφщ̆υ͊Ί̊ЌЊьΊΎΐϒьѕэяѓАΊѐґϊΏюєъόϏҖӔҒБѓԓЖΔ͎Г͔ҒϓїӓӐДёӕјҏҗӏԑ͊ʁzƈˑΒӐђΓѐЏҎєёՑӍҐЋђыҏјӒӖԘҒҒӒѓҗԜՒՖӍђӛԖӓԗՏҚחәӔӏәӘ՘֖ԓ֗՘ՑГҔӗҚԘԐӕՓӍԐҗԘՒԗԙԖӗӘӗҖҕә֖ӔӘӘӗՓӛӚәԘӖՖ՘ԗԕ՛Ԙӝ֮ڶ۶ٹټ޼ܶۮۨڝӞ֚֗ԝ՞ءؚٚՠ֢֝֜֟ՙ֣֗֡Ԛ֢֝סӟ֣רڪצףըبתٶ۾ݽݻܼݻ޿߾޾޾޿ܽ޼ݽ۷ڹ۴ְֵ֮ӶѶӸѸնӳԴӲԴӶԶִӴѲӵӵԵׯոҶӸַոֵնִԳղѱѱϰͰѫШЦ̩˨Ω˧ɤɤɢ̣˝ǜ˝ƠŞƟÜƘęŒřśē—”ÜĝàƤääêƨƮǭɫʪɰʳ̵̱δ˴˴ͷѻмϸеϷѶζϴ؛ɞȡɞɣǟ˥ʢ˟ʡˤɤȜȢˠȤʘɓɔȞɕȞƔřǘɖʚȔțɖǛɗɘȖǕɓɓʗɗǗƛȚʚ˛̛ɓɝɘɒƕǕɎˍɒǓʏȑǎɆƅDžɈɆƆʇȆLJ˄ɂ̀ȆɄˁʋ˅ˈ|˃̇ˇʊ̇ˆ̇̇̓˄̇̃˃ʅˆˁʂȍ̈ˈ͉̆̂̄z̉ˋ͆͋̇̉̋ΐ΍̐Ίˇ΍̈ˆˇ̇ˉ͊̉̃ˆφ͈͇̆͒̋̊̊̊Α̍Όΐ̊ˌϊ͑̍Βђ͍Ή͇щ΍Дьшύ͉ЌώΏΔϑώГѕΔΚЗЙ͏͗ГϔϗБϒЕГ̒ΖҘҒϒ̑Β̍̕̕ˏʊʓˑ̕ΗΑ͕ΒЇϏДϕВϘϒ͐яԎЎЗЕЕђёҕғԒӗϕЖђЗΕћҘ֕ґВ͛њՕԘӐӖәҕјє͗ҚӚєՓѐҒєЙ͗њѕіИԖҖїЗҙіїГјәӖёїҙќіӓӒԘϔҚїӖӗӔӛ՚әїѠӮջط׻۽ܿ޿޴۱٫٦آ՟ӛ֛әԛ֠՝ә֜աӝաӜԜӛӞ֜ўӝդנ֦ץաբդԦէ׫ԭ֫شٺܹڸ۹ٴصظڷپ޾ݼ׹عٻضصղӳմԶغ״ӸַֹԸַӴԸԵѶմԶִӵҴҵҴԵԵԶԳӶиָӱѯдͯϯͮͯΪ˫˪̦ͦ˧ɤơǞƝǝǜǙܝÚÔƘƙƗƔ××Б£ß£ŢâÞŤåæèéƪƫǬɱ˰ʶʵ˹˷ιѽоϽпջӷҳѶд͹ʹ٢˞ɡΞˣ̦ˣͤˤͤѤ̣̜͟ˤΜɡ˙˚ɛ͘Țȗɘ˛ʝʡʝ˞˗ʚ̚̕Ș˘ɗȒǑǏɒ˒̐ʗȔʘ˜˘˙ʕɏʓǒˑǐʋʋʋ̂ɂɅʅʋʈ̅ˀɆɂy~̌ʅ̆}~́́̇̈́}{˃ˆ|ˁ|̄̅̋΄˅Έφ~΀̇̋΄̓̇τ΁ς͆ˈΈ̊̋̉΀˃̈́΋·ˆ̂̄Ά̈́Ѝц͆ΐ̅ͅΊότ͆΍͇͑Ίϊ΅΋ІΎэЏ̆ΐщъёыґэАΊΆϑ҈ϊҍѕΑЕϑΔҔҕҔҌґѓҕґϔэяϐЊ̑цьҋѓϕІѐӋ͑ӐіђюьёӍ҇ыЗБЋҎьҏӏԌГяЎЏґӒҔӒӓҙԎёӒӚ֘֒ՙӓӕӌӖӓԒӓՑ֒ӗӐӒӔѓԕ֙Ԙԓӑҕӕՙ՗ӕՏԗՒՑҖґӓѕӗԕӔәҒӏқӒӐӍї֒ԖΘӎ֕ӖҘՖ֗֐ӗ֚Ֆ՚ӘӕӘҢ׫Ե׹پ޸ܱܶکأפإؠ՜֤֚֚֜֜םןמؙ֘ך֜ԟ֝Ԝ֣֢֝֡נקפ֤נ֢֧ק֬جڪشݸܹڴܶگ٬دܵݶݽ޾߿ݽܺ۶ܽٶٵַֻ׼ּٵֶֶشֵֶضֶزָնֶԵԴִӸԷնӷԶԶչӺֶӴҲͱѮѫЬѫͯЬͩˣɤǤʝ˦ȝǢǦǝȘƖƘǙƚƝÛƐÔŋƏ”ØÕ•Ý”’œŝŢÜŤǠǟģ¨ĥƧȦǧɰ̫̭̱Ͳе͹лйϻѽԾӽ۾ٻӷиδϻеԶؤ˝Ǥɤɠɤ̤ͣɨͪ˦ʦɤʡʤ̞ʞ̛̝ȞɚǗɚɝʙʘɛ͚ƞȝəɖȔŖȔȐɏȎǑNjLjɑɉɌɎˑɘɒɌɍƍNjǍLjȋʄljȄɂry~}}ǃƇ}ɅɅ˃̇ɂ}Ɂ}ʆɁrˀ˄ʁ|ˁ˅~LJ́˃ˋˊ́ʂˆ̊́~˃ʋ̇{ˇ˅~Ɇʂ΁̂ˆ̆˃ʅˆ˅ˈˈ̀ʄʆ˅{·͋ˁ˅͈̆΋̒ψ̊̋̋͑ψ͌ΕЍΎ͉͐̋Ή΋΍ђϑΑΎ͈ΈΓϋϒВΕΔϑ͘ϔϘИӔЙѕΒϑ͒̑͑΋Џώ̎Ύ͌ύΏ̐̌БΑЇΔΗϊΒГύЏЎϓЈˏϋ͋΍ГӏюѐϑϓДьѕӖӘәҕДяӕӖДӐԕӐюϑяѕӓҖјӖђ͔ϒϒәӖєѓՓӑГЗГӒҘјѓԔЕЙјіӒΖјӔϒΗҗђҎҒғёԚՕҗӚӗӕΙ՗ԓѓӚѐњјѣҪײպ޼۶ٳקء՘՝֠ӡ՛Ӝ՞ՠ֣֜֘՟֚ԛӝ֘՗ԟ՗՛ӛԛԛҚӠդרץ֧֦լ֯ױױװڴٸۺۼٺڵڳڸڶۼ޺ݽؾ۾ػغضֻػؽֺֺֹӶٺ۸ֶոָպָֻصӷֵӷֳպչӹԷҵԻԷӶұϯЭάҭͩέ̪ͫ˧̩ɨʥɦˣɢǝǝǛȠƣƟĝęƘ—Ĕ“˜š‘×™˜–››ţ¡ţ£äŤũƥɦˮɫȬͫȲ˲ͷиѷһӽ׻ӵӶϷѼһѷ٦̧̨̣˨ɦ̪ˤΨΨ̤ͤ˥ʦˤ͛ɛˠ˚˙ɘȔ˓ʝ˗˛˛ȚʜȖȏɐɓȒˌȏɊȉɉȄɄȄǃLJʌʉƋȌȌɌʁɋɌ˅ʅDžɆȂǁȂɁɄwɄ˃yɃǂ|xȀȆ͆ˁʄ{|˄̀y˄̂̂ʁ̇΀|Ɇ́ˁˊ̃̆~}˃ˉ͂ˇ·}Ɉ́ˆ΁πˀʄʆˀ̈ˉϋ̉̆˄́˅͈ч˅͍΋͇ˑΊ͋Ή΅χЋύ͐ˌΌ͎͌΍э͋ΐϒ΍·΍̌ψΏΎ͇ϊ·΅яАЏΐЙΕИЗҗАҔєϗєϒЊΑѐьϋшΌΈ͑Ί·ϑҍьҊ̌̑ёюАЇώϓЏуϊΏЋюДѓАБψѐӒӒҎяёҍѐїӒЖҐҌВӒԒцώғҐґЗҊэԒӒΖҘҖόҍҔґѕϗДϕђҋҍӒӒҕГϑϕЏґґҊҖӏѓіӖӐ֏іҘӕϖӗёЎӒҐӐғԕҚКўӢֶ۾޵۳٪֜Ԛԟ՝՜֡מפҠդؤ֖ӟ֜֡֗ԘӚҘҜ՗ՙטԜӚԜӨ֧֤֤ԩخղزرسٳڵۺڽݻܺۺݻݼݽ޽ݿ޾ݿܾغչֹؼٽؽؼغ׽ضԻַָֻضعֵַԺӷӸӸַָӹԷֻҹֶ԰ϱвЯЯүͰͰάϫ̨̩̥˩˥ȦĤɤǠșȠɟǣȝĢÚƚ’ƒÎ•֐ĔÒÚĚ×̚Ûĝ›Ù˜›śĞĢţäƨȦɪ˪ʫƱ˱ˮǯγѶθҸѿѽҽԼھֽշӸһԻӽԸبɧɨ̩ʧͧͤˤˤΣˣ̥ˢ̡̟əʙƕʕˍʒʌˌ˕ɑȖȐNjɍʌȈɊɊɍljłdžǁƂLj˄Ʌ~ǃɉɊȆǁɆʅʀuƄɂ{ǁwzsy~~yǀʀ~ɂʀtz|Ɂȃ}yˀ~|ˀ˃}yɀ˅ˀ}̆̃~wʄ~̀ʈʉ̀˄̃{˃r˃΁ˁ͉́΃́ˆˆ̅̉˂͆|ˇ΅ˈ͉ˇ͈͆̃ΆˁˊΉ͉̌΅Ά˂˃͌͌Ύˌ΋ˋΐ͈ˍϋ͈ύψѐΎ̊͌ϊΎ͓ЋΉ͊Ώ΋͐Дђΐϑ͑̕АєВёБΕΒϑ͎ΖѐьϋэБ͒ΑΎΎЎёЊщˇώЍΎΎЎшΏА΋ΒϒюЎΊόДԑЏЎϋґГђьΉЖѓДЎϒёΏӎђҌяђҋ̕АЎҎՍяГғҐѐѐыϓӑғВϑђғЌэҍғГВґϒҎґӌӐѓГѓϑӔӗԙӕӗӕҗДѕјӗќ՛ԤѩԶؾݻۮ٬ا؝ԙӛӡӘҝ՜֠զإ֨ץԝԞ՛ՙ֖֘՚ќӝ՝Օҕӝӡ֤ף֤էשֳ֮ױٳٳֶضٹڼٽڽݿۿݾܼٻؽؿؽؽظػ۹ֻ׸ػ׸۸ӻظط׺շӸҵֶӷӹԶոҹԺӳӲίЯѯѱаҮβίάΫ˪ΦʨɦʧǧʞƛƤɤƤȣǛǝĝƘƘÔŔĎęÜڞ ěŞáĜÙ¡ÞÛØ—ĚŖĜġœĘŠġǢƢĦȪȬʬ˭ή̲ζ͵϶ѷζѽӽֽڿپ׺շӶҷлӽոبɪ˩ʦ̤ˤͤͦˤ̤ˣɞ˜ɗȋƌȍNjȅLJɆƂLjŋ˃DŽǁȃzńwǁdžǁDžȂɂDŽƆǃȀv}~xƆƁɄ}ǀyDŽyxx{uŅ~}}ƁƂǃ|Ȅǀ{ʂȅwDŽʃw{ˁˁ˅ɀɈʁ˃˂zʁ|ʅˁzvʊˁɃ̆΅Ɋ{}ʀ˃̀ʁˀ˄Ƀ˂̉˂̃̃ˁ͂ˇ˅ˀˁʁˊ̈˂˂˄ˈ˄ˈˉ̄ˁ̀̌Ύˋ̊ˇ͍͌Ί·͏͎̉̅͋Ί̇΍ш̋̋̉̋Ή͍̍͊͒ː͎Ό͏ϐΐΕΕ͘Β͙ΕДЏΔΖ͕єϘҗ΍΍Αыҋ͎ы͍ΐ̐̐ΎΉщΉΈΒЋόΊώΏΒϑѕϓΉ̌ΌюѐѐΕБђ΍ΐόЉЇющѐΕѐΙҍЍѓёєЕΔѓєыΕϒВДЕώϑБђύϗђΒЕЍΏЎ͒Ώϋэӑϖ͍ΑΑ΋ΐҎэҘϒΑҒҒіӖӖґњϙҔΜӠӡԬصٹڹܾݿݾܵاԦ֤՗ҟԛӗԙңգ֪֧֩اפ֡ӛӗӗ֙ӘԜ֗ҙ՞ԛәңӠӞӨ֦֨תֱײױٳرٲزٷڹٽݿؿܿؾֽؼععٻָһ׻ֺԻַָԶԷָӶѻֶԸԸպ׵ԱϳеѱұѮбʱϱααΰˮ˪˨˨̫ͧʤɦɨǟǢʞǞƚƞƕęƗÓ֗“Ē•’ĘŖ™˜—ÛžÝßäŠßÝÝáĤğšǜážÞœâƤɡɟƠĠššȠĝÝťƢĜŦūƪ̭̰ʱ̱ΰαβѲϳйм׻ԷһҹѽϽҷڤɩ̧̡ͨͤʞ̛ʚʕ˕ɐʊ˒ˆǁy~ƂɀʂˀɅ|vsrw}wuwwzzǂȀ|xsxyvu{ɀ|Ȅ~~xƆɅdžzzȁɃywzǁzv{wwsr~~|z~wɁz|x{Ɂ{oˁ{Ɓ̃{ˊ̅vʅ˄͇˂Ɂ̂rɁ̀~ʂ}ˁ̀˂}xxʁ~̅ˁ̓͆˂ˀ̄̆ˀ}˄̎̀ͅͅϋ̈́˂ΊΆ˄΋̈́́Ά·΍Β·Ўщ͇͌ЉЋΈ̊΋ЍψωΌ͉͈̅͌΍ЎΓ̐ϘϛїΝҘљӒΘЗђϔϓϕҁ̊Ϗ̍Ά͇ϐ̋΍фΎΎ΅̍Њ΋ӌчϏЏЋ̏ΌΉЈѐяЈΕώуόьЊЋюӒюώΈϋЉΐҐґґҎБґҍшЋщϕΗӌΏЋ̎ϗӌђӔБωГΎВѐяёЏѐЊЎΈЉАӓҒѐёДѐґӓӋАђїѓӒҍҐѐҏ՗ҏӘӜӡӤԤԤ֬شܶڲٱٵܷݺ۷ݭ٤֦՞Ҕҙјԑ՝֝פզգ֤סן՟֛֖ԘӖҙӜӖҚ֙ԛӠբԤ֢֤ԡԦ֭ױزٲرٱضڲٳۻݾۿٽڻۻ۽ֻػ׻ػӻֶָֻصԵҷԷնԳҷԻغ׸ֱҲҵҷѶѳҴѴӵұϰϱϭѪѪ̪ͩЪΦʧʧ˧ɣˢɤǢɚǚƟÚƞƛŜ×ÔŖÔ–”ØÓÓĖÕԖŖƕ›ĕĚĔœě˜“ך˜œŜßܗƞƞŝɠáĤĞĠàɤʤáŝƠĢĜÝĝŠšȢŞŤŠƞɟ£ɣǤɤǧɨŦ˦˨ˮϰδαѳϳͱͳӶѼӽڽֹҹҸһֻԶ٧Ȫɢˡɤɝ̛ɗǖɖʇȅ|yt}łǁv~~ƅxyuzuvw{qx~zywyxydžz}{zx|zyyuvzǂyytÀłu|xxǁyÀys~|ǁŃƃu|x|{ˁ˅ȁz}w|ʂsȀ}}~||~Ʌw{~}ʃ}ɂʃʂ̈́ʅ{ƅɀʀɁʄ|ʃɇɇʈˆʃ̀˃˅͊˂ʂɃ̇̂˂̈̅ˋ}ˆˀʋ̉̇̌̄ˇʋ̋̋̑Ѝ΋э͋̌̉˅ˆ͉͎ϊΐ̊ˉˊˏ΋ДΒΘΘ͜ΔΖА͖іѓϖΖ̓̕Ύ͉̋˒̓Ό͎̌Ά̆ʎΏ̌чˍ͍ΏΌ͔͓ψΉ΋̎͑Ή͈̌̌͌͒ю͔χ̐Ό͉ΐЌАїΔ͐̋Ї͏ϑӋэ΍͕ΑΈˑ͏ГєґΓˌ͐̒ό͒яВϐΒϏЍ͑Ώϋϋ͔Ҕ͑ώ͓Ζ͍͋̌͐ёΖБЎϑ΍ђӎѐђИГΎΑϖ̖їӖΔϛҜӘњНՙԜ՞Ԣץԧצ֧֜Ԡ֚֠ԜϞѝҜѠազԣӥԢӍҜԗәЕ֙ҐМӘѝӜҤդѦ֤ըԤԧӫׯسײֶسֵط׶صط߾ݻݿݼݻ۾ݿغؿ׺׹ֺջֻֽԼֺ׻ԺԸйӹѹӹӻӻտּҶӶҶҶежӶҶжҶѷѵγʱаѰѮΫ˫˪ȧɧɩˢ˦ʥǡǣǛàßǜėĚĒØ‘š’řśâٚžƛڛڶĞƞààâƢãĢƪŤĠƧâǠġâǠäĥǣģšȟɣʤƥǦƨǨƩʨ̪ͭɮɱɱ˰αβͶηиҶ϶еҺӺսۿռѾѽϹ٤ɣȤʙʘɘ˗ɑȔȏȅ}yŁxvy{ǁ~z{rz}twyxqxqvyq|wvr|xv~{yvvyyxyxzo{x}tu{yƆƆɁ~xxrŀ}ǁ}wȄ|w|zwƂɄvz~ȁǂ|ɀǂŀuǀv|Ʌǃʃz~|v~yˁ̂ɉ́ȃɅˈ˃ɄȄɅ˄ˆʆˉ|˅ˈˇʈɅ͉͊̋͋̄˅ˆ˅ʋ͈ʉ̇̃ʍ˄ˏː΋͍̍Ќ΋͏̄ˊ̋̈̏ϐА͍̉ˑ̐ˍΒ̓Εϒ͎͒˒ʖΐЊΖ͋ΕΕΕˑʍ͆ˌόыΒˉˉˇ̊̇Ύ΋͌̓̌ˎˏ̉˄̄̋Έˑ͋̏Ά͉͐͋ω·̑Δ͒Ή͓͊Ќ΋ΒΑΈʋ̏̉ΒΎ҇ΖϓΎΑ̏̊ΊΑЍѐ͏΍̎̒ΑϏϐόΒ̑ΐ΋Α͓ђёω͔͖͒ΒБΆ͎̆ґЗА͑͒ёΒϏϐЕΐΓӕёяΎОҐИЗΒώЏ̏ϑϙК՝ҞҞҜҚЙҚҘҘӝԡӝԤ֥դӦԜ֘ҜӕіҘӗѝѡҡѝӣӢӧԤӣӞӣԬָ֯ٲֵضٶٷٷطظظؿھݽۺܳڶسڴڲٮشظܹڴ׳ڶۿܼܿܿݽؿٽؽؾԻջֹּ׸ֹԺպնԷҶжԹԻֿڻֺӽҸϸҵйӹѼӷննҶѱϴϴαҳаί̮˭έȪ˪ˤɤ˦ˣǣŞÚŘřƚƘŖĘ˜ÓӘٕĖܕ×ę˜Üœ ŸžšĜšÞ™ÛĚ  ÝÜĝĜáƤģâĢɠũåǩɣȩŦƣȦǪƤçȢȤǤťȩɧ˫Ǭ˫ʫ˩̮ˮ̴̰̲ϸͳ϶ιѹԽηӺϽҽӽӽֽҽҷأʟ˖̔̒ɒʋȊNJɅ}}{xurxvszwty|Dž{vrtttuyvsqoy}Ɂvsxuwǀzqvrp{wzu}ʁɄwvr{{ɀrƄǁ~|u{yyyʁuyu}xɁyt~{ȃɀ|suɆvv~}ʀ~ʀ{sy˂}˂ˇz}˄ˆ~ʃ̃}~ʅ̊́ͅ|ʁ̓́̊ˇˁ˄̃̃·ˆ΁̅ʊ͇͉́ͅ··ˍ͇̆΍͏͑ё͆Ή̆ˌ͏ω̈́̋΍͌̊̄ˍΌ̑Ἁˑ͌Ί͇͏ϑАύ͕Γΐ͑·ϋϏ̎ʋ̅̊ˌ͇Ά΄ΊЋʆ͌Ίͅωψω΍͍͇͈̈͊͋͋Ίόϊ͈ͅχ·ϏщѐЊϊόЊ̊͑ЍϊΑЖюΎ͇Ύˋ΍ύϑ΍ВВАюϊώЏϓюЍэ͊ЈΏшыΌ·΍Ќ͉͆ϐӕёΎχ͍Ύώ΍Ϗ̖ӖҌΖϕЉғӏБјјΐΎ΍ѕҗӘӒҕВЕҕђјҘӜӚԕҝққӣӢԢԧ֥֣֡ӣ֠ӖӚҗҟӒ՚ӠӢӤ՝ԝ֣Ԣԥ֤ԠӣӤӦӭ׶׵ٶشٲڰضضڹعܾ޿޽ܾܾݺ۹ݶܳ۫٪ժ֭ر֮ش۵۲ٷۺۻܾ޼ݼۺ۾ۻ۹ոӼּػֺֺոշշӻռֹջػ׺ڷֹԺӸԹҺԻջԷշֶԺּԸԶұұѯЮ̯̯̫ͯ˪̪˦˥ɠȢɞƛǛƜŝƚ՘šĕ–’Ö”řŖšœÖřƙĠƞǛĝƙşĚ¡ŜơơǡȞơƤŝÞÞƛěƜȞǜۜžğĝşǟÝƙơèǢˤɜƤǤäƢȤȢĤȨǤʥɩȨʧȥʥʣ˪ʩʦʩɩʩ˦˩Ϊˬ̰ʹζϴѶͶҲ϶ѹѸҼҾӾ־ԽԻսٿؾ׾׽ջڠǞʖȉŋȍʍɆ}xsmswurrxvwr}wty{|{qwvyxssu{ws}y}vxsppx|lz~|zȀpytuyo{{swuuo~xw{|z}|ȁʂzuv}~wzȅyzɀ~v{|ʂȅ~~~yzɂ}Ƀy~˅ˁˀʅxyɃɀɀɁȈ́ʀxtʃ˂{~ʀ́ʂˇ~ʂʆɂͅ}́˅ːʊ͑˒ϊ̍̕ЋΑ΅Ό΍͎͇̑͆΋͉͋͋ˉː͒χΒΉ̊̏ˉˏ̑΋̗͊Εΐ͊ˏˌ΋͐̃̀̇ˇˋ΍͓ΊЊΊ͆ˇʈ̌̈́̃̆Έ͌Ή͊ͅˊ̊ˌϊΊъΊ̇̅̎υΖяͅΉ͎ό̂̇ψ̍ӌҏЃ̅ˊ̅̉΋͉̋ю΍Аώό͉̍ύώώ͉΋Ή͍̐͋̍ГЎ͑ъΐϐΒѐёшύЊ΋БόΊΏΏѐЕΎБΏ͍ώϓђя̕ВΕΔяΑғєя͓ΘҘЗӔДДњӠԡӤԤըԡ֦םբәϜӗқӗњϢ֣צӪԨӥ֧֝ӝҤէԨէժس׷׶ظٲٵڴ׶ص׵׼ݽݾڽ޼۸۴رحծ԰׮ڱٺ۷ٷ״ط۹۹ۻڽۿݿܼټػۻؾ־ֻ׺ӷոӼջԹһֺ׻ػ׸ԻԼԻӻԺչ׻غֶӹոֹӹԶճӲӲѰѯЯΪ̮ͭ˭ͮ˩ˤɢǥǠğǟƜƙ™×˜™ÒØƗŘÓÙƙŞřęƚĞ™ğŜŝÞƢƠǣŧƤƣƣǡƝŚàţƣǝǝĠƝśÞßšǟȜǡĠƣäŤǩɢɧʤʥƣɧʤŦḲ̌ƨɤìʦ̪˪˫̫̬̪ͪʬˬ˪ɭ̯ѴζдҵϳҶеѵӹҽӽӽԿԿӽԾӼֻҿտֿѺٓǑÂǁyzxnvytsmnnm{ǁuvvrsvrru~molusrttrqtsrvovpvorsvvvxzstuÀzxs~rvrorr{stsss{||}ǀyzȁ|rru~xtǀyvsr}|u~tȀ}ˀ~tɁvs{z|u|̃~ʂ}{ɂ˅~~˂̀~́ɂˀ~}Ȁ{yɂˀˆ̇̉ˑ͐ΗϗϐΓ͋̒̌̄̈́ˇʇ͈̉̈˅ʊ̆̉˅͉ˇ͎͆ˋ˅̄˂ː̍͒Ό͍̋̅̉ˌˁ˃ʆ͋΋˃̂ɇ̇Έ̊̋˅̅́ˇ̉̈̋΅͈̈̆˄ˌ͎͌Ώφ̄̊ͅώ΄ˆ΋͆фЇ΋̆ˋΆшЇ̅̆͊΋̉̊ΈЉ΍όΏΈ͉̎΋͎ЎыΓЊˆˉˍ̌̊͐ΑϐΌΎ̎͐ΈΈΌЖӍяΎ̐ΏΎЊΌѕё̌Όё̕Ηϒ̍͑ЎΏ͕ЏЏϏДЌїєҘїДϖЙҖԙӞҜќԦ՜ԣբӛҒғϔќПϢѣԧةة֦ӣ՜ПӘӤխֵ֯ض׻״ش׵زױسر׵׹ؾ۾޽ܺؼ۽ٻڹسحزٰضطֶֺڼٸۺۺݽܽٽ۾ؼؿؿڼ۷ֹԺӺֻؽ׻ռԻռֽ־պչԸӻռֽչֺعճӵչӹַմѵѱѭϪάέ̨̪ͪɫ̤ΤȤȣƜȞȝǜțř•ŕƒÖחęӍƗØ×ĕŕƛßƞÛܙɟǞǢƤªŨȠʟǟɟƝǝƛŝşŠßŤǢǠȠÜà£şƟơġÞşȠȞǤɟʦɪɦʦ˩̦˪ɦǧȤȩǤ˪ʪ̪ͪʪ̬̭ͪͰ̯ίί˱βϴϸѵҶζ϶йѻӷҽ׼տԿٽվԽ׽Ҹۇ~uāvux}~wyrn~r}~sƅroxwvtpwxt{xyzwǀwslxosu{v}yphxwlvzrxÀ|rtyz|{rtppr}uytxvrvpwyƀ|wstuāuryq~wx}~x~́tƁʁɂǀˆ{~ʁ}~ɀȀʀy}ɁʁzȂˁʂ̈̇ʃʃʁ̀}˅ʁɂɃ~ɄɃ̀ʄ˅̈́ɋˈɍ̎̒̃ΐΊ̉˃ˁ˅˂Ɉ˅͉̊̑̆ˋ̆̊̎ʆʈ̇ˈ̌ʌˌ̊ˋ͒̌͋͌ˊΌ͉ˈʇˇΆ̋̋̂ʃˇˊ̋̋Γ̐ͅʅʍˇ˃˅͉̋̊̆̈́͌̅ό͍͒̎̉Ϗ́Љ͉̋Ό̏̑Ί·̓ΉЌΌ͇̃̅̇υΆ΍ΏΌ̉̎͊΋̐΍ˏ͈͇͌̈ωΉόΌ̉΍ύЉΌЏ͑ѐ·Ѓ͒Βэѕϑ̕˒ЍΑΖюӘђ΍·̑ΒΌ̔ΖђѕяВЏϓΐΖΗϙјіΘ͔ϙљғӕҞӞӞӞӣӜӞљҗџԢҥԦץ֤ԣҩը֢ԘҚњѡҨժկײٹ۶ٸضرײײֶ׶ټھۻۺؼٻ׶մڵظٹۻ׿ܾڻػڽٿھ׻׻׶շչԽջֽֿս׼ֺֽػֹսԼվտ׻־ؾֻ׾ԼֻԺӸӹպԶֶдϱίЭέʮ˭Ϯѫ˪ɤǤȡȚȞƝǠŝÚƙśėřؔ˜’ĕęŕÜÙÜŝŜ¢ĝÝɞĠǠȤƪȫͪ˨ȥɣɟǟơƤ¤ǢȡǥɣȢȢɥǧƦǣƢǢǠáǤĥǨƧ̪ɤ˧ʩǫ̯̮˰ˬˬ̫ɮ˯̮ǯήʫ˯̲̰̲ͯͰϲϵϵѵβζιιѻѼռֻػսۿҸtuqtv~yyvsxvxuvshszptnofqrquusnvqtpscwwrrtsxososvutswwsǁxtsvwortƂxovumrro|nlssuwwxwtuxr{ǁ}s{qvǀǁ}yv~xx}ʁur|Ɂ|yuzwȀ|ʁ~yvy}̂̂ʀ˃~ɀˁɂʅsɁ̂|}˂ˉ{uxɀˁ˃wɁ˂́ρ̄˃̆˅̓̀̉~΅̄̋̈ˉ̅̈˅ˇ̉̂̄˅̂̉̊΋̆ˋ̋˃Ɂ̈ˊ΄͂̊΁˅˅̊Ά}˂̉΄͆Ή̇ˋ˄̓ˆ̓˃ˇ͉˅͆̎Ћ҈όр̃Έ̅y͈ЋуόΉЊ΅̆ͅ΅ʄΊΊ΅͈͊΅̉ϑъЉ̋̊ЍΈ͇͉͆ͅ΋ΐΈ͂̊͊͊΋͌̓ЍІцЋ̍эёҐЍҋ͓ѓҐύщΎΎΈ͉Ћ͐ΒΔ΋ϒђΏЋЌЏБђяҏϔЖѓёҒҔϒғӘӝӜԙӚќњӞӠ֧է֧֤֣ӢԢӝԘїӔҚӚӤӧթְطڹٸضگֱٰٱչںپܽܶ۸ڶݻݻ޽ۼܷܺعػ۽ܾۿ޽۽ܾܾݾܾܾܿؽڿ׺׶մԶԸָԺ׺ھ׻׺ּֽ׽ٽֻ׽ٽս׾־ؾػڼؼؼֿԻԻոԶҵӱձԬϯ̫Ϊ̪ѧ̤ΥͧˤȢǠǝƛǝɡƠǟʚǘĕŕÕÖŒǑØĖÖƖƘÙŚǗƠäšǠǥȡɥɨʧ˭ͬʭ̫ɦɡʠȣǡȞŤʣˡɢɠǣâʤƤȤǢɤšȤƣǣˤɥ̡̩̤̩ɪ̨˨˪Ϊ̮ˬ˭̭ͬͭ˫̱гϴϵѵѴѲѱαϴҶҸѳѵиҶҺ׻ӻս׾ؿݾ׼}~zqv}krlvqnyuorlqotnoplmoptv|vthpnmvtqrpftnjosrƁvrqtxuvqvorvrprsrusu|vs|xuuwxuwrvŀƀƀrp{ǁʀǂ}}xxyy~zƁtȂv{{uʀǀʀzsy|~{ȇ}~~|ɀzɅˁɆȅ|}ʀʂɀʅyzzˀɀɅɃ}}˃~˂ʂ˄˂˅̅ˀˆx˅ˇˆˇˋ̅̇ˁɉʃʉˋ̆̃̄ˋ̌ʇʆˌ͍͌ˁ}~ɇ̄yʃ͆˅ˀ˅Ɋ΂̄ʂˈ̉̊ˊ̂ˆ˃Ɇɇˀ˃̅΅̊˄˃˅̈́̄˄̉̊͆ʇ̈̇ˇ̋Њ͉̂Ɉˇɇ˂˂ˇ̊̍ˌˍ͈̎̈͋ΊΉ·̍ˋ̇ˋΆ̋Έ΋̉̇̄ɉ̊̐̏Вҏϊх·Έ̊̇̌΍΋ϐ͍̊̋ͅёψΑΎˌˈ͍͊Δ͐ϓАЏ͍ϓҖВΒ͔͑ϐҔє͘ϗϛУӛԠԙљўѢӤԣԦӪת֦դӠӘёΒϘЛӞѢШҫԮղ׷ٶ׷ڱ׫հ״׶ػؽ߿ۺ۵ظػݻںܻټ۽ݽܺۼ۽ڽ۽ؿڿڿؿնӷԶӶҹӾֽֿտּּؿټؿ׿ּվֶֻֻֽӻԸӷϵҳίͬϪͫ˦˪̥ǦƦɡ˜ȝɞŚƘŚŚĜƔǓƚ“Ĕ‘ŌڞǘÛǚƘƛ¢Ǣǧ˪˧˨ȪȪˮʭ˰ˮέͥˢʢɡȥŤʨǥʥ˨Ψ˧ȦƤǣɣƣȣȢǤɣɣɟʦȪ̪ͪɩͪɪˬ̮ʮͯΫΰαβϱ̵ϰʹбджնѶеҲѷҵѵӵԹӷӻԻվֽӽ׼ֽutyrstkrpqutmrouelrjnuqmnrpnvklpqjllmutpkhtssrmjqtironppjqsuwsnkuolrvsspqsxpopttszqtz~rrou}p{Ƃ||soizvtvr}~{pxvyzqwlv~}ȃɂx~Ȁz{tȀǀ~yyzxǀuȄǁyyɃ~ǀǀʆ˃˅~ǀɆˁˆ~ʀ~˅ʁȈʃLjɇ~ʀ̂ȁȆyɃ˂~ˀȀ˃ʅʆ˄Ʌ̂|ʇ|ɇɂɁɃˋ̇̉Ʉ˃˅Ʉ́}˂ɀʃʆʄʁʇ̃̈́̆ˆ˄˂̊ʅ̃͂̀~̄̈ˈ͈̃̃΋͇͊˂ʂˆˍˆˉ˄̂ʋ̌̋̉ʊ̊ˇ͇͆Ά̅ˈˈʈ̆˅͇̅̉ˉʉˋ͍͍̋΋̅Όυ̒̌̍̇΅ΆΊ̐ˇΌ΅͍̇͌ͅΌ̖͔͑ʊ͓ΒѐϕАύ͑΍ЏёϏёΓѓΘϖӛѝљΕқӟәљӘӤԨթգӗљϘϙҙΗϝУҤӪӨөթլְ֯שԤӬ֮حֵظںڿܽ۷ٸظؽؿݽܹٹٷٺظۿڼܼؼٽ۽۽ڽڽ۾ݼػػؾֶָֹնԶкҼӿսվֽ׿׿ստ־ػվ׿־ؼսּӻԻԶҶα̭̪ͩʥʣǤȣƦǡȞȝƟǜŜږ–ÖĒÒŕ“Ƒ™ŝŝƠǝɝǡǤŦƨƤʬ̫˫̮ͮͱʭˮͬ˩̦ʣʥǠƥɢɩȩʤɧʨ˨ǤȥŢȧɢɤɡɦʪǪɩɪ̩ɫʩˮͪȪɯˮ̪̮ͰʱϲήѱбααϳжӷӶҴϴѵѶҸлҼԽֻռԻҼսվ}ywwpxliumutvqvxspllmqqmnpssjntrlcjn{lstsrnvovqnovqqmonmirlrpsvswpkpnzs|rqumpstsq~qmwx{v}ost}nŀ|{{|ttpsĀɂn{zwvx}{xuxsqx{uǁȂzp}ʂɄ|{zɃwu{xȀ́ʁ˂~ˁɄ{ǀʅ̀̆}ˀʃ}~ʄˀ~ʂɃɆʃˆɁʀʅ˃˄ʂʄ̃ʂɂʂˇ̅̃ʅ̋ͅʃ{ʁ˃̂˄̃|ǂɄɈ˅̀΄ˉʀʂ˂Ɉʄ̓ʅ̓ˀ}Ɇ˃ˆ̇̃̀̈̉˃̂ʃ̊Ή΄̈́̆ɇʅˊ͊̍΋̇ͅɅ̊̈̄ˆˀ͋̆·ˌʉ͉ˆ̍̌ˉ̈́̉̆̈͂̅ˉΉ΅͋̏̆ˇ̅ˍ͉͌̉Α̐ˁ͍̇ːΑ·΋͑̊̇̌̍ˎ̎̊ΐэ͎͋̍͒̉͋ΏВ͔͌͊͏͉͌̊ώЗӖЙїϑΖϑҍҐіѕΝӢӤӠҗҙϔԝѝѠәΕϝџӡ֡ӞҞԥԧգӤҨե֪֦ԭ״׿ݽ۸۷ڻ۽ټݽܼ۷ֻؼظ׺ضٻ׼ؿؼںۻڽؾھݾعغڻ׸ԵӷԸԺչԻԻ׽ֺֽӶҳѭѬϪϪɥʦʩɤʦȡȝɝǞŜƘƘÖƜ×ŗƏÙΙěƙƛƝƝęƖėƜƤɣƢǤȤǤɦǨɫ˭ʱήͰˮϱˮ̮̬ͬ˨̦ʦȦʩ˪˨Ȭɯɪ˪̪ˤȣȤǤɨʧ̨Ȭɪɫ˭Ȫˬˮέ̭ˮϧ̮̫αϭͱͲΰϮϰѯͰϰβҵҵԸԴζѺѷѼкԼؽ־ؿڿ׿vuw{yzknmnsqwkrpuxossrsqkoqompruirrslqrlpnpmmrpmjsoekpsyouuwsy|xtuuut{ts|uvotrtzws{vs|qo{x|vv{urtv{ʄ|vx~s|˂syɁwyzyyn{ȃǀ}{vr}zz~v|ɂuz~Ƀxǀz}|wƁłɅy{ɀ~}~˂|ɇˁʂ}{ȁʇˆ́ʄzyɁʉʅ|Ʌʁʇ˅ʄzȁʂˊˇ̂ʆ}ˀɅɂɆ̀ʂɂȆʄʈ̈˅˄ʂɁ}~Ɇʆ˄́˅Ɇ}̂˃˃̆̉~ˁɃʆˆˁ̅̅̇̅̀́Ʌʅ˃ˆʊΈ̆˃́ˆ̓˄ˇΌ΂̅ˆ͇̉̃˅͈̈̓ˈˁ˄˂̅·ˈ̐Ѕ˃͈̅͊˂΅̆΋Ύ̆̉̊̂̆΋ˉ˅͈ύ̐ь͍ˈʋ͉͉̏̌̇͌΍ΉΊ΍̐ό͇̉΋̎ύϐϏΑєӍΕΊ̌ϏчϐΕћќњҐϖѕϛӝїϙΒϑѓ͗ϔѓэМΝҕϛўҚӚҙӣӮշؼ۾ؽص׷ھ۽۹ںطػڷػٷڹٸٵָظּٽۻڼ׽ڼؽ޽۾ۼֹԸյԴֶֺպվ׻׻ؼֿؿػֶָӱӬЭϮΨ̦ɩȢȤŜȟɤəəƙĖŘĘřęØƛƛǝȝƝǚǜǟǠȡǜǣǠɣˤȤǫʧɨɨɪ̪̭ͮέϰ̯ѭˮͫʩ˨˧˥ɪȬ̫̭̭ˬ̭έΫ˪ɩȥʤǦɩʫʪ̱̬έ˪Ϊʮ̯ͬΰϮί˱̮ίв̲̮˰ЮΰұѲϰжѹзηѺӶӶһһѽӽԿؿտ׾nlszmtvypuoqyrfmploophkhqnnoepjtrirlloqjmmnjijmoriqqpunpuuŀvnqtstƃuuspruu~vt||{y~vxx{~|}}wwwwttjjsz~|xvq}vɀppsxsx|yy~|w~ys{~|wux}wpvzxnw~yx|{}~vy~ʁɅ˄̀ʇy}{ɂ˂ʀɆʁzɂʁ˃ɄɀɈ~̂ɀɂȀɄʌ̅ˁɁ|ɂ~ɁɁ~́˃~zˀʀ̄}~|Ɇ}Ʌ}}ɀ~ʃɁɁɆ̀̀˃˃̃̂́̃ʆ˂ˇ̈́xˆˇˆ˅̊ΆˁɆʇ̅̆Ȑ͉̃̅˃ˁ́ˈʄʇ̅̌Ό̋̅ˊ̂˅ˆʂ}̀ʆ̇͆̓ˆ́̇̇͆Ίˉ̌Ό͍̉̆ˍ̍́˄̉̆ˆ˂͈͉̌̐ϋω͑͏ΊˌΎЈ͍͌̊͐Ї͋̉͑͏Ό̑΋э̓Βю̋ΒϔΗїϓђ͑ΘѝӚјϚΑϑГΓΜѕΌΎϒϐя͒ϛϘϚϟӟҡ԰׵ؼܾ۵عٺغ޽۴ض׳خײش׵ٹ׵ֶԸִֶ׸غںڼֽ׼پػؼعֽؽֹֺԶԵӶԶӻս־ػַԸմӱҬЯϫ̨ͬȤɥˤʡɟȠȚƘęșŘĚƞŞǥʣɟȠȞƛǠɞǡƥȪˤɧʨ˪ɨɩɪ˪ȭ˫˫̫Ϯͱα̬ͮΫ̭̫ɪʧɦˬʰͭ˩˭̬̩ЦͦȦɥʪ˪Ǩɮˬ̪̬ϰΩͰέɮγΰϯѯίαδϰήΰбеβεҴжѵҷҶҷиѶӻѺӻԻӼӻջ׾ֿؿԿk~ruoquuosogsmlultmkjrokltuofkmfnhprmihdipoljiijmtlijrkpntmxuumzsÅxmtpsqyrtww~ǀ}svtpzt}sgpmsoluxx|lqqsvvsuormrttqs{yy{z{xwuutvvxrnqprzvr~rxv}~swpuxwuwrzxˁʃȂȄȂʁɀ|~Ʌ{~DŽx~zɂ~ɊNj̀y|yy|~ʁ{ɁɀvȂ˄yy~}|}ʀ{z~Ɂɂ~ˁʃɁ˄˂~|ɂ̀̃ˇ~~Ȃ˃x}ʄ~ˁ̂˂ˇɄ̅˅ˇʈɌzʀ̄̆Ʌˁˁʅ̃ˆ̆ʂ̄ˁ˅ˁ˅{ˋ̉ʉɁˊ̋͆̈́̂ʂ͉̄̍Ά̄ʃ̄Ɇ̈˄ˈˆˇ͆̊ˇʅˈ̉ˌˌ͇͉̈̂͂̉ˆ̅ɉ́ˇ͌·̎͋ό͇͉͉̌̋̆ΌΐΑΑ΍ӐΐϑґˑΏ͖іϓː̑ДКЍ̌͐ΐΐЗђњΠϢОѠѡӥӲ׹ؽ۸ضصضطټݾݻݴز֪֩ղֵֶطسڳֵյճԵֳֺۼںپپؿؾؿݽؽٻֺֻ׸ոոնչԷӶӹԸպԼӻ׾׿ټӹѵӱѭΪϬΪ˨˥ȡʡȜǜȞȝǟȞĝĜƟɠ˧ʫ̫̪έͧʟɞȟɦ˩̨˧ʫ̨˥̤ɥʧ̦̬̬ˮ˪άήˬάͪΪΨ̫ʪ˪˭˭ͭͬͮΪ̫ͥɦʥƥɤ˪ɫ̪̮ͮͰάЬϱа̰ͱ̰Ѵͱͱ̲ѳ̳ζζεηϲгϴѷѶѷѴҶӷҷնҷӺӻӼӺԻսֽԾ׿uxpwpsplolokklenqyxslrnphopnrgf`ospkqkpmsmmoxiqpsyrrsnmykouy~ƁwyrkÀsxwyqtwywrt|yvrquǀzxvmvunnvxǀoussro|rxv}~roywowqumxqvtwws~~w~v{Ɂ~susunu{pxvu{yzxǂz}z{ǁpv{ȃ}Ƀ˃ɀǂ~Ȁwy~}|ǂ~}v|ǁˈ˅˂Ɂ}}~ɁyǂɄ~x~ˁyDŽˆˈȀȂ}ɁɄ~Ȃɀǁȁɀ~Ȃɀ˂ʁ˃ʄ~ɂʄ˄˄˂{ˀDž~Ʌʂʅ̆˄̅ʅ|ʃȂʁ˂ˇ͌ˉˆʁɆ˂~ˇ̄̇ʂʅ̅ʆ˅˃́̆̊ˏˆˆʋΉ͇̊Ό˅ʅʂ˅̇ˆ́ˈˆˉɄ˃ʁ˃̆̅ˈ˄ɉ˅ˈ̎Άˋˉ͏ϊʇ͊ʋ˅ˈˆˉ̋Ή΍̈̇΍͐̏͋ΑΐΏ̍͌΍ϙ͕̎͐ϔΗΑΓΑώГΓϕϖД͙͘РϥѪѧѦқҞТѧӰ׹ݿظڴְְֲնֽعֶر֯ԯձְְְֳֳַֻմմֵָ׻ٻ׼ٽؿۼظ׹ָֺظӻӶӷѸԹյպֻտּֽֿ׺ԵԳаЭͮά˩͡˥ɢŢǠɝǜɢʥ˦˩ʪͬϮ̯ͮͮӬѪ̠ȡȤʤ˨ʨ̨̬ˢɧǤȩɤ̪̮̪έέ̫Ϊ̬̬ͫͮΰ̮ή˪Ϋ̪Ϋ̧̪̭̮˪ɧǨȩ˦̮ή̮̯έϱ̯ή̮δͰгγζηвҶδδѶγζϳѷѷѹѸӸһӹӹѹҸѻӶպһ׼ҾӿԾonmvrrpijgd_jrtholirqqvnmiliprqnmnmgoeoojnlhmrqyxxqwpusxvsolvwttmosmuozynqqsxrsrr|vsoouwywppouzrspnvquunuvstnowxqvxxwlpquqyyxrovtq}vvpnvxrwvotvwɁ~ǁɂʂ{{ȄʀʂʃɅwz~ʂ~~z~}ǀyɄzɁ|v{ǀ|Ȃzv}Ɂ}xǁ|sɀy{|}ɂyxwʀɀ~~~~Ʉʂˁ˃˄ˁˁ}ɂ̃̄~ʅ|ʇɀʄʂ˅Ʌ~ȇ˃ʆ˅Ʌ˅ʄ˄ˈ΄͂ʃɇ̅˃|˃˃|ʄʅʅ˅ʄ˃|̌|Ʉʁʄ̅̉̅̅ˇ˃Ʉ̂̄Ɇ˃ˍ̎ˊ˅̆ʁˇ̅ͅˉ̊Ί̄ͅ˄΄ˉ͇̌̊̓ˋ͆ʏΆʊ̌̆ˏΌ΋ϑΎΆ̋͐ϐψ͇̌͊ʉ΍͎̑ϖΔΓЕϙΏΛќϟџҧҩԩԧӝџҤөԨԯ׵ٻع׳֯լ֪زֶ׻ؽܺڸڶֵܴطػְִָج֯ճط׵׺غٵ׶׹׺׼ڽ۹׺պֻջֺֻպػֹջԷֻջػػضԶӶѲѵЮϫΫͧʡȥɨʥ̣ʠɥɩ̪ʹԶձҮϰϰӱϰѱΧ̥ʥ̦˧̨Ȩʫ̪ˣǦɣģȦʨ˩˧ͪ˧ͧɪɫ̬̮ˬɬͭΫЬϮέͩͩ˩̦ͩ˨̪ʩ˪ɧʯίίγѱγεббαϱѵѶҶгѭγжӺӹԸոҸѹѺѸҶӷչӺӻԺѺԻԹӼӻֽؾտqorjsntrmn_rrtlroqsjimqnnni`kifhiwhnejqmsstllqquszwqslwwuusmvrnopxpxuoqoorq{sr~sqqutqoskvgvqsovlnnssƀwrqoqsrjlqqsqnvrqxsorovqpxxtxxtsxvvpxpxxzuo{uvǁmɀmyz}ʀɃ|~wzvvyz~~w~ǀ{xzǀɂ|y}ɀ|zn}|ywzʁɄyɂ}{|}ʁz{Ȅ}{yyy|}ʅ}ˁu~Ƀ˅~Ʉz˂ˀʂxɁȅȆ~Ʉɀʁ˄ʀȀˆȅ˂ˇʂt{}ȅʅȂɂʃ}ˁˁ˄ˆʊˆ̅˄Ɇ̀Ƀ̅˂Ɂʆˊ̂ˀ˃ˆ˄ʄ˂Ƀˆˆʂʆˌ˅˄ʂɄʁʈ̂~Ʉˊ̈́ˆˊ͇|ˆˆ̆ˋ̇ˌ͇̊̉̆͋̋΍΋Άɇˇ͍Ά̍̐̍̏̔Ύ͚͒ΠѥҤѨӪӬԩԣѤѥңԡѧԳ׸ؽؿܽؼٵجӥӨӫԲӹֿؿ۽ڻ׽׹ط׵ٺںسײְֳַ֭׷شٳ׷ּػؾۿڽؽغػӸֹֻӸոջջػֽֽԼؾָӸӶղѲүЭͩΤ˜ɟʦʣȧ˪Ȭʮϯ͵ӱӵзԹӵҴոԱҬΪɪΨˠɠʦɦɡɤơǢǞƞǟɚʟɢɦʩ̦˪̫άήͪˬ̫ͮͯϭ̫ͭ˫̩ͨͧʨ̩˦˯α̮̱ϳαҳѴѳбгѳѶеͷѸӶѸӻҶӷеӶϵԹҺҺһӹӹԶѹӷӺӺҼֿԻԼӿoeainmle`ioihf\\^gjnkkjogfplfdd`fjomjhjkottotnrorhgmolnmrvnnqqijnpsswqnnllpnnommirgfpurvproipzvosmmjoommtrojlovp{vppsqjlplmslmpopslpownrxrjxvompuwuuqrxptlzryvxz{~u}x|~|vz~wuyɀxɀvurǀzy}|ɀǀwzyxǀȀkw~zz}|~{ȂǀɁv{~}w|ȂzɁ~~x}ɆDžɅɅˀ̄ˁ|x}Ȉ}ʂ{w}|zȃɄz}ʁȂ~ȀɁɀ˃˂́~ɂȄɁʋʂʄˉʁ˃ʁɄɆ}Ɂ˄{Ƀʂ˂ɄˀɄ˅Ʌ}Ȁ~Ȉ˄ɂˀʄʃʅ~˅˅̈˃Ʌʀ˃̆ˁʁˉ}̄ʆˉ̊ˆ~˅ˈ˅̉ˊ̆̉ʅˑ̌ˊʈ̃ˍ̋͏΋ʕ͚ϝФӢўѥ֧ҢПТќљФӯֶؼ۽ܾںػس֬ҦӧѬӳֶ׻ػٿھۿڿ۽ٻֽؽ׹ֵر׫Ԯֱմֱ֮ӮԲֹ׻ؾؽڽظֵӻظջֶӶӸֻ׺ֽؿٽۺյҴӶҳбЯΥ̡ʤȦ˥ʦ̦˪έѭѰѱҰҰϲҵֵַԳճԫѪ˪˧ɤ˪ȥʤ̠ǛřŠƝÚśŚǝȠɠȢʥʣʨ˩Ϊͮ˩̬˪̬̰̬ͯϬЪ̫̪ʨʤɦ̫̩ΪάͮдбѲѱγѱгѰ͵ѵζѹѺҶѻԳַѵҶѵеӹԷѶҺҹҷѷҹҺһ׽Խӿ׾ԿԿlsklmelfmqeqmbonnshddpkgaiggohknmopmkwnztsuuwwpyrrkopimtlwvpronrqmnm|suptmnhjhkqspqoprrytvijrrrruwpshopqkcsrorqoqqrxtmqiqqwuqnknit|psutqlvuwzry|pjy~|yv{y~uwƀw~|wkuy{~~wyyȀz{rz~yzwxz}w|x~ǀx~~v}~ɀɀyxɀ~vxʁ{ȁst~Ƀy~vʀ˃vx~Ƀ~ˀy~~yɀ˄~zʁȁ˄|ˁɅ}˅ʄɇˀ|Ʌɇ˄{ʀɀ~ȁȆʃ}́ʂˀɆɅɁɀtˈˊʅʂɀ}ʆˆʆ̃ˆ~˅ɁɆzʈʈ̂ʆʄˆʃ~Ʌʄ˄ˉ͊̆ʁʀʊ~ɀʇyˆʂ̃Ʉʃˉ̉́Ό˅ˋ˅ɄɆˆɇ~·Ί̅ɍˍˌ͆͏ώДϘϢќјћТԠҢѡϙΏ̢Ѯִؽݿݽڽ׺ҵֱӮ֯Ӯն׽ּ׾ؼؽּܻط׶ر֬ԬլԫԨӤңҧӳշ־ݽپ׼۾ٻԻնԻԻ׻غֺһӾӾؾٽ׼ԸմԲβͬʪʣʩ˨ͭϰϯҴҵҵҶҲѰӴҳӷӳѱѮѫ˪̦̠˦ʢɠˠʟǡǢǛƛŜƜƠșǜɡɦȢȦ̪ʪ˫˫̪˫˩ʰͰ̱ϭή̭ͭͮ˭˫̮ͬʯʮίγѱѱѱϲѵιѶϹӺѶҶӷӻּԹҺָԵҴзҺһӽӻӺֶմӺиӼӾ׾׾ؼֽֽӾpvoorhokekgsqr`holooimgmcdibfrpollkpvyyyrxqponsputomqqkrjw{noyrxtruknppovmomlpnsvqtwpoqlnilqppsqomlmuokokioonjsmmttvqxlpwwvmplpqklsvvprowzrnuygp{wm{}yvuxzrrx|{uyz~~xwy|~wytyyu{Ȁ}qzvw|}{}Ɂ|zɂ~zuzɂxwqǁxy~u{ȂwȂɂɀ~~uw{yɃ́~z|˃ɂ~ʁ~˄{ɀ|yzʁʃȄ~ʃ~́˅ˀʄɅ˃~ˀ˂ʁ̀~ʄˀʅˁɀ~Ɍ~ɀx˂ˁʃʀ˅˄˂}~˅ˁ˅Ɇ˃}˅ˁɄʀʃ˂˃̀ʀ̆̅ʁʂ˂̃ͅ˅ʂˆ́̃̄˂ʌʁ̃ˁʅ˂́ΈΌ̑Όwʁ˃̅̉͆̄ˋˉ͍̇̏̋ˊ˒ΐϑ͗Еэ͒ϛѝѡКЕГМѩӵ׻ھٿۿؼڷָ׷׵նַսظۿؿڽپ۽ټڷ۵״׬ԨգҡҤҡӞӣѱշ׿ݽ۾ؿؿٺֻػ׺ոֻ׿ؽؿ׿׺׵ֵҴϬͮϮѮҬЯ϶ҴӰѰԴѰϰаҭҮϵѯϰЭӫЫϬ̢̨ʤ˜Ǥȡˤˢʛȝǜɞǝǡɠȟɦʣʦ̧ʪ̯ͬͮήͱα̯ΰѪͬͯήϮͮЮͮ˱ϭϪϱβӴвѴбѵշкһһѶԻպֺӶҸԹԹӺԺӸնֵչԹӺӺӻԺ׺ջԻؽؿֿؿmrjrnkq]mohquggjffsdikipkljkpvyxtrsmxxvxrmrunjrxrsvnsr€uqtooytlwsyrngqpxnsjlkmtuomqjllrmeiqnr|vpnpspjnpkhumqolp{wmnljus|mhorpwqlt}ppyfnnwmrn|mxqovy}zrnyn~~{~vwu{rur|~yvwopxt~yvrvxr|}ysvvzuu~~wxw|sǀʁɀ~{|{ɀ|s}}}xɀ}ȂɀˁɁy~ɀxȁ}Ɂy}ɁvƅxɈ˄˄ʄˀʂ{Ɂʂȁʂ˂}Ȁ{ɂʃ|ɃɄ~wzɁɅʄ́ʅ˂}ȁzɈ~ɃɈʅɆxyy~ʆʁˁ̅ǁwʀ˅ˇˁ̇̅Ƀ~ʅʇʁˁɅʉɁɈˁ̃~}ʋ͉͆̋̅ˉ̆̇ˇ˃̅ʊʉɇˉ˅˅Ʉˉˋ˅ˆˆ˃ˉ͇͈͉̋̍ˋ̖̐ΖњћҜѢѬӷ׻ۼٷ׻׹ֻּٽؾڽؿؿ۽عֵװ֧ҢќϘΛϟѠѬҳպؿؾػٽܿڻٽջּ׾ֿ׾ؾ׼ֹӷѳӰұԱѵгԲӲѮүѴӲӫЫЮͱѰӳҶմүЭ̩ʥ˧ɥ̢ʪʤˣɠǛÛȞŜƝɢʦɧɤ˩˫̫̯ͯͮϰϮίҰͪΰ˭ͬ˯̰ϭ̪ͫ˫ˮήΰѱҶҵβѳҶӹҶӺִֺּӲӷдҸҹѸҺԸӹӶӺӹԸԹӺջԼԼԻ׽׿׿ּٽnp`ko`jkeilk^gfoh^mlefhgkmroqsqvvās~{vwuvsosuqpisoskksimeoikpvtlokwtqwrympfnilgpqommpigrjimdojbrrorljhikcroqjlgkhhpplqomrsrxqjwshlpypsookusyr|rqhnutrpwulswvqrqppvsyq{zvyo|yxqwy|~spÀyqvs~vzwu{vyxƀyz~|~}{{rzƃywuwȁɀwŁǀȁɂ}ʂˀˁɁʀȄʁyz~}xDŽ~}ɀ~~z|y~~{|}}|ɀ}ǁȂ}~}{x~{ȁdž˂}ɁLJɂDž˄xǁx}|}}x~ȇdžƁǂxȁ~~ȂɀʄȀȀ~ɀɇɀ˃ˀʁɉˍʄˁɈʄʇɂ̆̆ˈ˃̃ˌǁ̅ɉ̅ʁDžʇɆˇ˂Ƀʉʆ˅ˇʃɈˋˆˉˋˑ˗͚͟ҦЭִ׸ظضԷظԽֿٿ۾ٽزֱ֭ӢҗΕ͊˖ΤЮҵպؾؾ׽ؿռӻ־ּֽ׽پջպղҰжԵӴӶմԳӱѳбҮάϲϸѴѷѶҶϰЭϨΧʩ˩ɪɨɢȢɠƠŸƜƞƝĞƠȦɩʩʧ̫ɮ˭̮̮ϫϮ̯ͭ˯ϭͮͮήΫͫˬ˯ͰˮͲдѱӱҴѴϵλϻӼӺӸӹӹӶѵѶζѺѸԼӻԷҽмҷҹѹԺҸӽҾսӾӽroljllhpjllnijhdjlloopuqzwrw}trxmwxĀwupsompnstiqxprpnmmvtrqppkptsimdnovsqvnkiejvlnljninlkheljnrnsimg`lkiroullnmjkholnqpnovjtoljpkpnrlmrrnlnrpqjpuyqnklɂpsrkutvtuwjxluswmit{|}xzvyptowyxvpuxsz}{{xy{|u|{wwz~x||y}Ȃ}|~ʅɀ|oƁ}~}Ƀ}}vɁ|yy~tǁɁȁɁʂɂ||ǁ~zzɁ|{ɇˁȃɂ~ɀɀˁʀȈɁʀ}ɀ}ǂyȉ˄ʅ|ɂȂ~xɀɆˉɁʃȁɁ|}}˂˅Ʉʁʂʀ̇~ʉ|||˃˃͉Ίˁˀ̄ˉˊˁ˄̀ʀˀˀɆɁ|ʄ̐̄ˉdžʃˇ˂˂ʅˉͅˆˉˋʈ̈ȆˊΓ͎͕Зϡѥճֲֵձֲӹ׽ܿ׹ػشذիԜϖΒ͖ѨүԲֺټپٿ׽ֻؽֻۻؾݾܻظ׹ش׷ؽշԷֻּ׽ػ׺ֱֲѯаϯѮѱӶֳշԷӶӹѮάά̭Ѭ˫̧ˤ̣ɣɤʥɟʜǞǠʧɥʪ̫ͪΪϮͮΫʩ̮ή̮ѰϮѫͬέϬέ˭̮̬ήϱεѳѳδѵѶӺӳѻѷӲԴѵӶѶԷӷֺӺӻӸлӽӻԼ׼ؼӻֻԽ׽Լ׿׿ٿhgdkhgqkmfp`smmjrqsuv{woy}|x{xv{ywxuysrvxormunhpfiomrpgmttjjqillrlhlttlvxrt|rmacfjkkdfikhjpipisffmlzlnnpylmmlrnjpslmlqonjqglhmzmtkmjninqlmxpqmmppqozpqyosrrpoovvltzzuruwysvtwvzsxr|vwvuǁ{}vzwx~u{v|{u{tzƁxqtxǁ{~{yzƂʇ}v{|ɀ{{~ɀˁˆzȂɅȄɁʄuy|ɀx~{wȁɅʄ~ȁz~|yɀ}~~}~ɂʀɂɀ|Ƃ~Ɂ~˂{Ɂvɀ|zɉ~džDžz~}ˁˆ~˃~ɂʆˁɃɅ˂˂ʂ~Ȁ˂˄ˁʊɀˁ~ˀ̊|˄ˇʅɆˁʁɁɂˆ~Ʌ˂ʅʈʂʁ˃ȀɄʇʃˆˇɀʊ˃ȇʐ͑͒ˑ̏ΚФԪֱժӣҪԶԾܽڷضְֱ֮֨Ӡϙ͒͟ѭԮӲյյպ۾׾ؾ׿ؼֿ޽ܻػڻڶֲשӥѦҢҦԪַؽڻڻؼؾٽ׺ֹճ԰ұбϫϬϬѴӶҶԷҳѮѱЮѬѪͰЭΧ˩ɦʧɢ˥ˤȤɣʣʨʩ˨ͫήΰͭˮͫέаϭϮϮϮέͮ˯̫άΪή̮αδжзжպӹӼֻԶոҶѵζдѲҷҼؽӾֿռշֻּҼֺҼԽռֽֽؾؿmnkrlfjulpnrvumruxy}}y}xĀwz}y~tx{yrlusqwoqukjnsljjjnikpwllkljkljfnjkuxtusppkmfeeemqginljedgjplqf]dkjootrskpundkiihosfglqofgiifmhmsmhmljlnnrpmgjptv|nigksrspjplplmmsxyxvnlqsxuqowqrouvxur}Ɓj{yo}x|vrvvyxw{w{rvz~wxzy{xxzzǂǂy~oƂ~xǃɇ~z~oŀzw}xx}~{yr}|Ȃzrzwǁv|wȃ{x~~yƀƁDžǂƁɀ~Ʌ{~v}ƀɅȂuǁȂʁ~ǀʅ}zɂz~{ȁ|ȃ|ȃǂʉɄɆɀȄʀɃ}ȇʄ~ɀɆɃ~ǁȂɂɀ~ɂ́ɃȁǃȈȅɃɀɄɆɂȌȑ˒̗͐̔ЛГ͗ЖΖΘͱҺؾؾعضԶ֮թԤѣϟїΚ͟ЦϭѰӴֱӰշؽڿٿؿٿܽ׶ثթԨҩҦԮհ֥ϛЕΖ˗ʔ̤̑̑ϲհճӾپټععֽ׽׹ԸӷӵϫѪ̨̮ͮ˭еҶӱέϩά˱̨̮̪ͦˣˡ˩˦ʦȥǧ˥ɩʪ˩ɬ̮̭˭̫ˬ̯αгбϮάʬ̬̱̮ίϯήˮͯδηѹӾӻһԻպѻҷӼҽѺָҳջϿ׼ԻѺӼӽӽռ׺׼ֽԿsilmossrprpsvur~u~ƀ€ąz{Ä}{}xusywtxwtrqqrrooejumrnnpfmnnerjejrmjkpsltnivmptllfdirkojurtkniirolpljglos{pioomhgnpongkgmoxgpbrkhkjiljpmhmtqcnildgxxpu|uwkvkqlrqvprmouzquw~uxyx}ƀyvpjvzoy|wszus{v}{vÁw}}zz|w~z{Ɓxu|ǁzwy|v|ǁ}ǁ{svy}yu}}}ƂzĀǁ}zuw~z}|~||ǁz}vzǁ~ƃƀxy|Ȁ}ǀz~v}~}Ȁǁxzɀ{ȁz}ƄʃɆDžɁȀ}ɁȂʀɃ}}Džǂy~ɈyǂǂȅǁȄʆɄɄʃˁ|ɀɁɂɄɅɁɅxǃ}džɀDžȄʆɀʁɂǂɄɅʄˍˋʒ͔ˎˉ̖̑̎̐̔ˢιؼؿ۽ټֻԳӬӦѠіϔИ͘˗ͣУѭԵղ״طػ־ؿؽۿ۶נϚ˙ΐ̑їΘϒ˘̓̒˒˕̎ˉʈʐ˛ϜОϯկקӪԴջٽڽػ׻յӴϮϰͰέ˯ίгҮͱбϮΰаб˫̮˪̫Ϊά̪˧ʦʧ˧̧˫̬̮ͪͯͰβаͱѰӱѰή̮ͮͲΰ̯̬̰̰ηαͶѹӿؽֽһӻҾֿտҽӽԿڽؾּһӼҼҿӽԿտ׾oonmlkkjuovzyuŅot…w}zzń|yunnwrtv|nnlgokgjfolhrrmqjec`dpjoqhiriijminsonlgdlmpejhkkbenjjpdrhlkkmgnkrrnofjlkhmglnrjflookgaqjcfejjmjhoghqplpjjdgxkiikojljplkvopofqnlulkjpwlkshrwvgixrkmgl}unowvxv~yuwxrrypzsxoqjvnvrywvpqvy{x~ow{vxyvvsvxzxvsywouwzwt{ƃ|y}yxz}|{{zǀ{yvvy{}~zx~ƅ{rǂǀƁwy~ɀz|ǀ}z{}Ȃ{ƁɀǁDŽȀɀǁ~yvǂʁʄɀxȅˁvǀɂzɄ}}ƁɃɂ}}yɀzɀʄ}~ȁȅʁDŽɃʆɊʉʄʆʇ˃ˋˉ˗˳Իػڼط׸ؽֿٸ׸װ֩ԖΗ͎ˎˌ͈̋̉̑˜ХӮԴմֶ׷ٿڿؿ׻׼ּ׼׺ڻֻֿۿۺڱؖфʆɅɋ˖Βˊ˒̒ˏʐ̎ˎ˕ˈˌˏˈɌˌ˕˝џўЧӮն״շֹּ׻ԶӬЯԱήϭͬЫΫѬήѯ̮˯ͭϭ̭̭̮ЪΪ˨̨ͧ˨˨ͨ˪̪̮̯̯бίαвҳеѱˮ̪ήΰΰίέέϰθζдѸնѶҼԻ־վֽ׿ֻֿնԻӻҼռ־׿ؿnforotu{zƃƁƀzvpxy|}qŀĆy~vww}xlmiltsnqjlghkelmltagkkhjgfahdl`nrltloiojprmrfagiinmjikhjisgro`kggo`hsjmtsjjprmjljkjjkddkkkrefnjhiegjhhqmnomqiplmpmnjkilmljjmihjmlpzflntzomzlmlp_xtuqrwqslxo}yxsvlsouoqter{z{zt{oqt}xtspskqpuvo{xojnvo|wyzuƂ{yx}Džwztq{zryw{zyrƀƀ|y{~ǁpxt}u}x}xǀǂɁʀ}~{{LJ~tzƃzǂ~ɀȁɀʁrz}zuȂɄȄ~{xdž~|Ƀ}ʀǁ}DžxxǀɀȆw{ǀ}}ƀƀȀȂʀ~ɇɁȁȂȃy~ʉ˂ʄɆ̄ɏˢӯֳش״صֻ׿ؿۿػ׶֯ԥԕΌ˂ɏˍ̖͋̎͌ˊ˔Ιѩүմֺپ׿ڿپؼػػַֻֻӹ׾ؿݼܻܸڸ׵ׯ՝ф˄ʎɂʃʉˌ̑̒ː˓Ε̋ˉˏː͏˒̌̎ʋȈʕИΖΛ͢Ө֟ѤҩӫַֹԯӯӯӬѫѭЮϭѱѪάЮѱͫΰίέϮЮЪϫ̬ͫͭα̭̬ϯѰѬͭѲΰϳγүбѭЯϬͱЮѰήͯϱѳӷѻӹӻҷӺҽԷպջջԼֻֿپӼԷֺԽջԻֿoxz{}Ć|Á~}ŀĀyvryĀ{Ąr{{u}utnprkqkorvonia\edgkickjjelkmdefbajgnqmidnjluwpkbhlpxnefhjrkfakinjgjllmnlojolempihfhhnklfhjhj^kkmodlflojpkjhlicpllkjjjnilqklplmjnijjnpirmpptsuqpnlnpmkotvzrxxjxtpnvvvsrmuusmmnosvvvlyqvsyptysw{z|vvxquuv}rvzǁvvw{yvz||zr}w}||vux{nwtywvxzxsyw~|}}~xywwzǁƂɀzǁ{|ǀŀǃ}x{ʁ~zɁz~yɀ}ɂȄʇȂ}|v}|ǀȁ||{||ˁɄ{}ɃɁxƂǂʀȁȁ~Ȃ~}ȀǂȄȁȁwȀȂɀɄʅȂxƍ˒̝ҪңҥѱԺֽؼؾطյׯӠϊˍˋɊ˄ʇʅɉɍ͎ˏ˗ͦӱֶ׻ؾ׾ڿؿٿֻԽؿ׾ؾ۱֢͘ύɍ̉ˉˆʋɑ̎ːː͎̔ʗ̐̒̓ˍʑˎ̈ɊͅɇȄɌȒȎʋʗΗϐ˓˗˙ПͪӱԮԯѭϪέЩѫѱҮαͰάѰͮήͬаѮΰέϯЮίϮϲβζβҰӳӰδвβѱϱΰвѮήѱϱбвαҲѳӸԺӻչӼӽԻӶѶӹӽѽҽؾֻֻһӼӸչԻսֿ݀ÆĂÀāă{{zz|{~~Àvzutvxxvrxspnkmgjjcm_lfkedkdjg`idkdddedorkltrssvruszvvlsnjojoktmrjlkhifdhhepuyursljjfkojhologh`jflghmjkqnipjirpef^emjthccimvmmgjkjmsoqkltmmtsoolnqmlqrrqqlppxnrr~lrxvxnuor}tympvyssslsnvq{plpr|yrwy|roolzyx|oqswzpłxyysvzw}~{zvzyus|wŀz}uƄxsvoswvƂz}ŀ{ɂ{ƂɁ{~wyǂ~{yyǁƀ}|}}ɀȀɃȁȂz{|ˀɀDŽȆȀ~|u~Ȅ}Ɓɀǀʀ~DŽdžɂȅwȃǀǀǁdž{ɀȄȂLJDŽȃʃˉ͉ˑɍɚΥѯӶػغپظرԠϗ͓Ώɇ˂ˁȇɈɆɃ˂ȅ̕Ϭҳջ׹׺־ۻؾܿ߾ݭՖ̑ɂȉɇ˄ʇˇɆɓ͔̎̔Ώ̑˓Ζʒ˔̌ˇɆˊˊ˅ʍɌʊɏˎȑʕʕ̑˓ɒ̖ʕ˟ΩҬӭҭѩͧϮЮήζѶίѯӳѱήѰбδҴѮҬѮвұвϹѵӵѳҴгͲ͵ӵждѴαϱѳԴгѲгеѹѻԻӿԺֽԻһѸѺԺоֺջؾؿֺֻӳӴҴҹѼӻԼս܊|}z~{z}}{~{}y|Ŋ{vz{wvynmutortwkghgejkfleljkjigdd`gega``klegqrnpdllqvx|€|skkolihjhnnoj^hjnfonvihldnlnmhmjsoomlqelkdejmkijeiijnoimkkbe\hnkolcij`gle`okjognjqmoknkntvnhqipsqyupvrkursuƅvzuysqusuv|wlkwyrrpuurunwxlnotvsnxxtqnovvuy~xv}{twuyvyxy~Ɓzyzznx|z{yzzzvy{yƂywuuoȀ~zwyy}u{}ŁǁȀ{}ty}z|}v~|ǁǂy~z}}~zʂȀɀuzDŽ{~ʅȁɁǁ{ǁ}ǁǁǂ~ȁǀ~{ȁɀ|yzƄƂƃŃɀȁȄ}ȁDžɇȉɌːɑʘΙ̣гԶصָسծԨϖ̕ˈ΋ʄˀȁ~LJǀȀȉŗ̏Ӷ׽ֻֻվٿ׾ۿظַػ۽ڻؽھ۷ثթԨխ׺ٿ۾ݱ؟ӏ˂ȆɂDŽȊȋɆ̆̑ˆ˅ʊʊːȏ̗͗Δʌɇ˅ȇɋʑʑʅȋLjɎɕʔ˒˖Γ˒˓ʘɖ˞ͤͬѯίѪ̨ͭήαѮίѱүұ̱бϮѱϰаϳдӮαвϳϴѸѷԷӷҳϴҵӶзδηζιѷѴжѵϴѹҺԽֽֿտ־ӼѹӽһӽֺѻӸԺӻӷӵдѱϷ϶θӸּӽ݉~|urp}{t{|z~Á…nosxuvwqsoloqqnpqmif[ai[^b]Xd^`acg`iVSdmikihgfbgpw{|wz{wq~jbZfccgijidjkjmkhoqljrigbbomdooglnjjhidefggiihcc^airhieX]liblg_]gdbhnejphijllklkojlklglrpllmrmomsxsrlvlrrvsmxuoovmnxgoomhsrsnportpmyxwnwisfmsqquomluvsuyyvuwunjuv|Àzqvpquwr|sytqycwtyzl{xlxuxmyvz}{y{|yw{y~zǁ{zyy{}z}z||y}}}{zx~ywǃz|~vǂ}~~|{ȁysw{ƀ}sw}{wy{x{t{|~vwu|ǀ}}~}vƀǃ}ǍȍɌɒ˒ˠΡӢѧӦҨѣ΍Ʌȁ}ǁȂǂȂǁzǃɇȈȠζջֻ׺׺ٽ׿׾׿ݿؼ׿ۺ׵ըӬֱӱհӴֶ׻ؾٻش֫Ҙ͙Γ͐˥еֹ׼غٯԱԲզёʇɅɂǃɀDŽ|˅ɊˆɆȅɍʉʅɎˍˌɎɊ˂ǀljʇʍɐɑȈȆʈɑɗˑʕˑ̒ːɖ̖˒˗ə˧ϬҩͩέϭˮΰͮдӶѳѴҳааϱͲϱӲұдγгζ϶ϳӴӸҸѶѵѸҶикйѻѹֹԸҸӹѸҼּֿؽֿ׽ջѽս׽ӷѶιдѶѸҲҳαϵѷжӻӸӹջؽؿޅ}~wrt{tuxpvwvvyprsvpwspjmkij]hkafef`bi\]\_\_^_`Y\d]c`dbi\b^eijmuryz~tlp]lljcgg_Tedhjnjqlimmdijlifgkqnpnhdf]a[fgbied`dndggbde_`bdkilp]epllhjjehflkiihdajknhdiojjekktwjioomrmkkllmrsukmenuomznsnfhqonlmpolghroouhovpoqvqr{vqtrmivxjoxpmrvt{‚snnpvxsptsnvnuz{jxusrwwnuwuy}upuxm|~y{wy~{z|{wwwyzvƄȀ~}vzɀɀǀoqzuɁ}ɀzz{xx}wxƂttx~yyuv{xqwywvwyw~Ƅ|wwDŽɅtsuƂǁǀLJȋǓɆȐɐˋ˂ȉ˅̋͋ʂx}~DŽzƃDžƀ{NJɝͩӲԹּ׼ؿؾ׿ֽؼؿٺػ׽۽ػطػڶխդЧўΤϩԨҭԸֻؿڷ֭ӨУΦϓ̏˛ͱӶֲ֪֤њѢОΏˋˊɁwǁɅɁ~ȅ˅ʆ˅ɉʆȍɑʑˊˇʊȊȊɈɖȍȇljɌʛ̘˔˓˘̕˕˒ʛ˗ʖɅȕ˝̠ΪѭΦЬ̮ίίѲѶѷӺӽֺӸѶѶжҷѷԶҹӺҸѸӺӻҷҹջҾջӹѻһӻռԾؽֽԹѺֻ־ؽԿֿѽֿӽֶּֽѷѶ϶гѳѱѴжжҶѸ϶йѻԽֿ־ֿ|z{|~}psv{ĂzvvuxurpsomomnqiqjefcigbbUZXZcaXo`icW`\_[`i`[ebiSjhopz}zxtswmimclgfiffafceplunlseoplsejghhfm{tugdicafed`fjhdcinlehfikpidcdbijfgipobabsejfnjkaijlfnmpmnqmlgtrltmimunoprprwlvwligisjtotwjjonomjtnlnoswotqqxzpuonqyvlpxsrvpsxoylmtzrvrnuvvupwroquqnywvu~usrz}stvz~tyw}wrzǀƀzvu|w{z|}}usƁt{|Ȁƀy|}Ƃ~|y{vvy|v}{xǁy}vw{y}{zyw~ytvxuw|ut}szƂƁǀǃ{}ȃ}y~ƂȆɆɒˌʅ{ȂǂȅɄɀ|~{uǁƂǃƇȄdžɆȇɒʗЩӲչּپۻطغ׹ֵָرתձ׻׷ְժӸڷحըҜѣј͛ϞѠҫձֵ׿ںزְԯӣѓˌˑ͠љϟϚΕϕ̔ͅ˅ɆɀdžȅLjɆɄ˅ɂɅɅɄʅ̋ɉ˅ȆȐˈˊʉȅʈʇˎ˔NjȅǓɗ˚ΤО˙ʙ˙˗ʕ˒ˎɐʗ̖ɐ˙ʩѯѫЭ̪ήήϳҶѸԻԽ־׽׼ֹԸӸնԹҺֺսոԻԻӼҽստֽԽԽ־־׽ؽ׽ؽּؾ־ֿؾ׽عַԳѲѷӷѶӵѵжеӸҼӻԺӽԽֿށx{ursvyxy|y~uvrqopsoveoqhoiigbdhc[cc`b__dcWfjii_Z\X_a\`ggg`bbllvwwāppknlhkghgnjg^a`enmhnpspokqjlkf_eieksrljpigfdp`_^bdgfd`hjhj_ejk`fginc`biefmkdehdhvjlellcehleplmtnkfinjojljjklleukplqljognopqopwsrpunpnnoonpnqkspip{hpoiouvztwunyw}ouyklhszwuwmxq{sovqtsqrwwuyyxpr~~vxxyxvrtwrv}yȂpyy~~}ǂx~}ǁw|ƀ|~}w}~Ȃ}~vzx|xDŽ{su}yn{Ɓ|}txu}~Ȁ~rv~oÀz{yz}t~ƀDžƃ~Ȃ|ȃȆ}Ɔ~Ʉʊˀ~ȅ{yxzǂǀȁy}Ɓ{ȃzǂȇɃʁʂɋ˥ѭԴּڹذֱձ֮ԬԦРΪԭ֩ӢѪйػֶիѤХќРљΗ͗Λͣе׼ۼܽٵ׭ӰԮ֘ϊ̆ʌȒʗ͖͒͐̆̕Ʌ}ȁɁǂȉȅ}Ɇʁ|~~ǃʆɍɑ˒˓ˌʅɆȉɃɏȐ̔̕ˏʘ˘˝̦Ϣћ˛̜̒˘ɕ˒ʐ˗˙̜̗ʡͪӣ̩ͩ˯βҳӶԻԾֿؿپٿ׽ֻպջּԼսֽ׽ּֿ׿׿׾ֿ׿ػؽּֽ׾ֽ־ػԱչѶӸѽӻշӷҺѹҺӼѺӽּּ׿ݿuxvuvrvxxymstvtpqhisjdjpkfli^Y_W[YUUZ\X^bORc\XW^bZbUQTZcg_[cebijmpyvsvwqrqjpeda_hch^T]bmmmfiknljehlldmfhgcdjihcbfhfac_XW`fddafcb`^V`^^^Zaf]dh\_ek\efn_difgcgdjhcdbgfllnlfcfkijjvmo`jjoeg_lkjlnisnmdnmmpnoolkjqnohgjlnhmlcofqgmfmvqfloivpjlimmmlijkqmqĀrovltqwyuwrnsmpsmspqjjxqlsmswunwzxvytt{vzDžuwwtsszzxxx~zuxyyrsutsqwuy|tvyzwvxtutzwwrxruzxtsqtvzvxyzyǀwzwztv~ƅy|{ɁɁ|Ƃwvxvx|{}zzur|{ȁNj˖Ϛϫӱ֨ԠѤңϟΙ̛̌̒ϙΗΩѵּ۽ص֩ӦϦѣΙ͞ϗ͑ʒɋɤϯӱֱײשӤТџА~ǃ~ɇˁȂˁ˂~ɂxy~yy~ƄȂƂ}|DŽʃ~ǂȉɑˑ˗ˈ||Ɖ}LJɏ˛˜˛ɚ˝˘̜͝Λʚ̕˓Ș˗ˑ̒ʏ˙ɠ˞̜̚ˠ̪̭ͪίҴҸԽ׽ؽ־ջֺֻֻչּּֿؿ׿ػ׹׻Իӽֽٽ׿ֽҽֶֻԶֶҳиԶ׷ֺԵӸӸӶԻԺӽվսսټԿտ۽ٲ}ruxtyoxs|nlppmuuojkimjieifdV^_Z`Z[^TW`bVa]UhUYWYbWZjfj`djkrmsswswkqpnnfaidccddd[\iglnhhggfhinll[edmaafgjgfkgphe``_W]^^`h`g\[[bbdgje^_]iedef\`iccfdf`lggfbfebfhhalgflvle`]feeienmehpkltkfnjmoojhnfdpmimgjehhhmkipikipuopjkijkeiehojgntppmfokqsvsusqotqsrwtroqprrsrqtyvuukpvrttxtvuoxxttz{uwqoz{ǀvwxzuuyqtv}xvvv{~vvwqqysyuu~yxuvyxw~ywwu|ypuyzzyprqvrytvrmvy~~{}~zvz}ǁyy{|}z}w|}~z|{xy|}ǀȅƅȉȞϚ͓͓̘͙ΐʌɌʌɉɌ˩ѵֽٿۺزױӱӫѪϩңϤќ͗̊Ɖǘ̘ϚΓΌʉʐˊƁzƀDžȄLj|zu}ǂ}rƅtĀzƃ}ɄDŽɂxnjʓˏˍyz}ƁƉƑǓʛ˝˜Ξ̠ˠˠ̟ˢ˚̕˚̚ʕɗɗʛɠΟ̟Πˣʢ̤̮ϮбζԼԿ׽ֻԿֽ׾׿ؽԻֻֻֽ׿ؿֿӽԻӹջַѷе϶ҷҸһԻռҽӹҼԼҽԽ۾ڲӭ~uzy}t}wrzyursuumjivmtmjhdfdbba`bX\b_`bXZbbg_WY`Y_db`dghZ``dkpu}€…ztpptlghmgZb``fgidibhjdkleoi^gcfoinljlljgllrjkmhahdgk\`_V^dkidca]dhihljabdgnjinbaomcigni_jfjhgjbmqojgifitoojkjgqonligjmgkvmf`knnmmrnilfkfktnjinfjnomqkujjkkrwsorrlmpskmmrrnuvpkqu{tpjquo{qy~wzzyurwwrltzwzt{ptxtzs~|{~{y}{wuxxyƀ|{twx}yy}zx}|w|yŀusz|{~vyuxnt{oyzyqxtz{vq|uxusw~xx|x~zƁ}{vw{}~w{yƉȄvyǁ~{tz~x~|~ł}yÀ||{ƀ}|ĄƉʉʂȅɆ˅ȁDžɇɃƍǗΧұԳֽؾ׽ؿؾٸ֫ӯԯհӬҫѥϞП̕ʅȈLjƅȆƄ}ŀǀzǃƅyƀz~ɃƇdž}|}~}~ÅdžljvƁ~Ƃ~DŽƔɌʀɂƄƂƅLJȎȏʖʟʣˣ̡ͤΥ̥͢ΤΟɝ˚˖Ǟʞʛˡ̦ˤ̤̠ͦѫ̮αгϺӾԽ׺ּҽؾ־ֽӻչԻջѹ϶ѵԵҷмӽԾٷ٬֤Ҥа{v~xyrouuyumslnwylejmjec\je`\YT`c__^Zcad\aad_PX^b__[Z`SYY`bnsy}x€~|wwrmedjka^\cbc_h`hiieo`lph^]_lfaenivnpkmihktkf`e_ackfad`bfedc`eb]]aedgbdi`fcpcrggocdlgfhhhimgggejiokkkqjsijkmplllkmjpgdptoioimwtqnkfsikjlnjniihoqlnunijmnmrjmnospnnqtmojrttvxunxmtxppspkwmuv{xysrtyokj~ovtyvzzw}yxuq}~xzw}tu~vsxv|ǂ|wwxv|{yxzyǀ~xǁwysx~sqwwxƁuzxr~zwv|{yvozutvƂw{|ǁǁvƀxyƁvzxy|Ɓp}{{ǃxyŁǀyvyƁx}z}xƁƅɁǂǃsxyǃɂ}}nj˖џѪӶոؽؾֻس֭ӫҨѢѣСϘϗИό˂wƃ~ɃȀȂǂxƁǀǂzǁǃy{~y{}z~}~}DŽDž}~|o}~ǀǂȀȃɂɆȃɂ}ƀȂȅɍɛΤ˥̨ͨЩѥϥФΤ̤̞˟ˤ̢ΙΤХΪ̠ͤͣͥ˨̭ѭӰԶռؽۿۼڿ׼ּջֽ־սӽԺֻֻ׸ֺպԷӻԽҾڿܻگ֮֫Ҥϣ͞ΟΥހ~upsrrmjmohjjenncg]^fYS\Z_aWXVSY[UXUa[b\VWV]ZVV_\b`]Z[`\`Zgprszuw|Àtvtn^df`_[U^_higeZ_]`Wch^^]beb^Xlkjdcakbafmbc`i^`^^`^c``d_bYbZbkk\jbe^kei_hnlddfjce[]bedkdaf`nagnkckfif_jc^kmicmilkdjgjkmpmpwmhhikjkeghmpgooijqijigqodmtghkgslopwlnhotuyukkomkmplstrmrlqnw{yqxjxpvsettywo{tvuwwypy{wzoqqvstvqszsqtxwvx{vywliz{yxt}{zsuzzys|wlslqptzwyuuzvvxxtu}|ruwz}u}ŀǁywxyzxtĀv~|xzz~v}vtzv}stvvsƀzx}wywy{||~Ƃn}ɁƂƃụ̈́ϱضظص׮ҪУΔ̒ʒ˓ˈʊʉyƀ~xw|Ȁ~~xty~ǀxyuǃǁux~}yz}Ɓƀ~~x}{vȃzǁ~ǀƈȅdž}yŁƏɔə̟ͧѭЩΪΦ̤͡Τ΢̢̥͠ˢ̠̜ʗ̡̢̟͞ɝɡΠ͡ˤ̩̭йֽؾٽپֽڿؾ׶ղ֫ӰѵѺӼֽ׼ַֹӺѺӽعԺԻԺԺֽֿ׿ۺפϠͣΛ̗̝˛˜˦oyvrohjiefnho`ln^c]\eikeZWb\ad`g\ZT]][[c\T[Ra\\WX_b``a_Zb\d\kmnsrvxtvvyutmdg_Z^[STZbiagR]Xc`^S_ccgfe\b_eee_b_h_Z]_b^\^^fWU]Z]`\gcZdcdaaada\ie\ihckgl`caidihfhh]^dchfimcdijkkqifehfawiljvgghghldohgmljimi_ajiibibnijmienihpjnpggkntmooljsmlnlnjllnmlwunnooprrquukrxtuppsouux}vwxsuoxxxwnuusnuuvwzpsvvsvuz{}|{ktttwv~xpsy|yrwxutyzxxuruttsxyy|xsnoqvsxxv}~r{}ŀ}q}}yvzvr{vxw||surps|uvw{zxv~xz|zvrv{xyy|zǃƀ}}Ƃǀwnjɉɓ˯ѰӭӫӛτɆDžǀƂǁǂtx{ƁĀ|}}|t{{Àx}{vyǁy}~z~~srwā~|xyytp{ȂƄƀzvŃȂǀzńƑʐȖʡˤϪΩϩϪ̜ͤ͠ʠ˙̕ɠͤ͝˟ɛɚə˙˞̙Ǟˢɤˠ˝˛ˤϮӮҫѰӯԭӪҲԱӱӻֽؽؽսּع׹ضӳ׮ӫФΤ̤ЧάѮѳӰӱЮбѶֺԼܿثљʘ˘̑˙̜̔͜ˢpdki`mf_j^e^\_d]ge_\\Uf_dYWSS`WY`_XVVV\ZYZYVYYSY[XWYYVX[[W\Wlnpjmixquwwmg^_U\R\]^ZTXZV]T`\\Z\b_ga`_dZ]X\_dYeZ^Wd``_[^WdYaY_WTY^Yach\\\\agaYbT]``nfdf_^]cf`cddg^`agihkegcgjfjlbde`bh`dhiffe`eckmeo_geejgjlldfecgjupfcidbmgmnhelifitysmjpl`ajnrllmkqyloidjihqoorksnlrmngqumkqmkmssrljrxs|ttssvwxspswltstzyuktpvxxsvruuyxvuuwpy}vxwwwlshqwvsrrvqstpuvryxpwvtzttxwy}nuzuuyvrxwvt|vuz{|qrqxyuvxutsstrtvuxsrss|xŀx~t~ǃʞϩҢѝΎʉ{uwǂ}uuvxusƀvwvyvvtzyxrvuxrv{}ǂvrn{tzv~tnsyyw{ŀŀs}w}ljȇȈǑǟ˦̩ͭΪѥΝ̛ʠ̖ɑȆȅȑȒɘɘʗˏɑȘ˖ɖȜˡ̤̞˜˚˜̛˗̖̘̕̚ʠ˚̘ͥЪնָֹԽ׽ټؿټ׻ַնմԱҫөЧФΤЩΤ̡̡΢Μˢ̠ˣПϡ͠ΣϲӸԼ׿ڹ٥Ϛˏ˖̖ɖ˗̕ʞ˥opiigdkojjdeZgeekcf^RXYWYT^aVXXZXT^dVO_U\VS]`^QXWZ[]SZXWUWWZfytplhmntvwyohbYVSXWV[`YZUa_RX^`\[`hhdcVWVY]W_`def]`b\YY``d_Z_]____^b^im\bbb[`X_aa[d\_f`k``Zdefifbjagd^icgagjfkiicojenjghlbenhhijeigdqkjjjlhiepllkeiighkmjhcfj`mmpmojmilopowlmlslzilpimpnulqvssnnovstvioiiqou|smirrpueovzmymsuwznusssx{zv|uvqtmyzvnswymy|vzpssqxuvytv|wxqzryyxlstosxrtvvtvxto}vkzvtwzwqtxtqsorx}~qquzvxwtvtyqwĀĀ|vzwtxtvyxuvrsvywwttyłƄnjˎˏˈǎǃwuv|ttvs}yn|y|ttwuwuq{}uy~n{y~wuuy~Âuw|xyo}|āƁxy{ÄńljȓɞʫϮά̨Τ̛͟˕ʚȑȋȌƆǏLJǓȗʓɒɑǔǕȓʖɞ˝˛ɝˡ̝˘ȗȑǖʜ˙˘ȗʔʛ˭βҮѯҶֻּնӰӲѮӬѪѦΣ˞ʟʡΨΨϨ̨Ω̤̤˟ɞɞ˛ˠ˜ˬμӽ׸ӤΝ˔˗ʗɋșʕɘɞphmmijdf_bd_hg^_]fYWc_RU[^\UWT\XRU[[W`YUXYSVZ\STZWXVWRSRaSPT]inojidipotupda[XRYSRLW\WWTf^T\W\RX]c_T_]g\bbce__^T]bZ`_dY^VWXb^bfYYc^lcbZ^_c\aX_aZdhc^ie]e_de^\ca_bfjfmc^afhgelchcedejlnjceddkeiikegfggfkkmpkehgikm^dbdchalnidbailmpnneissmsfjmhhehknokdnwnnnlotmsnoksllpjlmonioxwpsntos|utqvsqrvrrsiklpwvuwuqwzāyuysuzsyu{yuuktuvsrvsuvvxsszyzspluoy{vssxwrtsvxmr|vqvuxuxlusqoxyyuvwytvsrswvtvx|urrqprwmnotwtx|r{wy{}ɀxyxswnv|wxzuvpy}ruvyx|xtvsyvvvuusu{~rtx}ƀy|ywvzƀ}x|uuy|ƅƄŇLjƘǢ̫ѮέѫЧ̡ˠʘ̘ˑɍȋȅNJNJɕ˓ɓʌɇljȊǕʚ˛ˊʕʚ̚˖˕ʗ˒ɖ̗ʘȜ˗ʋȑʟͨѩϥάӪӫѬέϭѮͬѫЩΨΤΡΨϩΪЪТΤΦΨТ̧ͥΟ̛ʗˠθں׽׼ظֳ֧ҡ̛˔˒˙Ɍȑ˗˖˦njggmodm[c[`V^Y\^c\UZ]Z[ZVTYU`]^aaWUYR]YZYRRV[ZOUTWWT]aQ_cXX^iiohcejjmokka^[S_QOU[TTZ_dSWPOS\]ca]XWVZ_^X\SP]``bZ^[\`Z]][V\\[\aaZ^_\Z]]ZdbXe__e\^_fbibbajiab]Wda^\^`kf`eecfibfgklc`hiagijeaheecfj[fbccbicmbhghedkdmdggnghhpllgbjjhjjiigjnfdlodkpngklsomlejppkmpfmdkfiwrtmimnjnyplpyqovrr{usvwsoslorrqv}wpuyvpwxxynumrptwwnvwmkrsyruslisuowkoxqttusspwuwwxussqy|pv|ulpz}zwvrxjvqĀmtuoossqstuyruznwzwwurxynsyŀvvvswpxyƂƃ|ǀxslvyvmtztowsuyont{wupwvzyysvvupzmjlstƀ}~{xvpxzvx~w{yv}DŽɇʋȔʝ̥̬ϬѬҪҡΚ˚˙ʒɕɊNJɊʆɓɓɔɊɔɒɕǓˍ̘ȋȍɒ̎˒˖ʌ˗ɛʗʖɕ˓ȏɐ̘̕˚ʛˡͣͨΫϮϱѱѴӮϬϧЪѫЩѫͫͪϩΫϬΩЧΤϤΜ˗˙̏ʩһܽ۵س٫ҥΪѢѝΖ̗Κ͚͘ˑʕɌɓː̚ʩdW_geb_ei_e]`VY_\\XNSWSYRWWRRZSTSZSUNXNNSTTURORPQNSUSRVQLUTTW\Z_ncelhlg\bbaXROT^OYORRUORPXOS[SN]T\[\U^VZLN]R\]^XZU]UZ]ZNaUTa]VQ`UXb^[V\ZR^aXZL\Z\]dea^a[Z_`bb`b`ab`_e\gi_dnc]^_dddg\Zdb`]bffeeZggad`W][dg^dd_ae`bejohbmbgckh\fi_agigdjacdkljlllffkfejkmebgqnjilnjjhhqiyvkegukmisosjkkitstprhlrmqipnuntuljqjspllrlrlssptuf~tlvkjiollmsskkhopukkiktksstlwqkjrhr}purkpisfgluvutsoumpulroputtsrpekopikqprolntlguuywzuxyswƂtƀtiqqwrqurkrulquttturhs{rmrmtrwwluyrknsptgxyvsys~wsvzĄƌǑǗʡ̧̩ͨήϬ̧ʚɛ˟˞əǓɋƉDžDžNjȍȗ˖ɖǘƕljȊɍǍƑȎɌƒȓnjȒə̛ȓɌǎǑɚʠ˜ʠ̢̥˫̭˱ͯѱϲѶЮ̬ˬάͬέѭΰήαͫά̪̪ͤ͜˗ɑȇȐ˛ή׼ؿڲզѷش֯ӼضխөЦ͞˛˛˚˒ȎƐǐŊnjʔʖ˓˖ǘəɚǠ__le]`\XWV_ZY]WWYd^Y[X`XY\YRTZ]NXVWYXb\QYNQSPRTWRTSVYQPWQW[XZXcixj]_g\`_gi^c\URVTUQ[VYS]Ta[\V\]P[T]Z^Z]_V]^W\`VWa`]X\`X^R^\^`]deb`]_Z_^[b_```O]]b_\]ff``dbhheZa`fdhc[`c_e`dkebdjgadiafc_agjYhge`cfghccglffagmjkcd`hf^em_illgdkqlheg`ihlliej_ijmnmefdqlnfhjnkikmnkkohpiqftsm}nlprxstmmflsgrqquotpmwuxxwmnooorutmjqnsoqryvstsksmussnkotrwtssmousqnotmrsttv}xvmsnxxxtulwtqzwptwvrumuomqsnorqnruvmontpptrvxrrjdpy|yrruppy|unsrvtrmyotnrsvuvtsvwuovruuwjsoxsuygxowyzusuo|ssxyu|x{}}ĆƍȔǜɟʤ̨ϬбϮΩ̤ˢˤ˧Ц̥˗ȏǓɏnjŋɕȖʖɔǖǏǕNjȓɑɋɕɏȎƒɛ˟ˢ̟˛˓ɜɢˠˣ̣̥ΩЯѱδѴѵѲѲѱѳնѶвЮϳѱбѴұӱβͭΤ˝˘̉ƋɍƎ˔˚ϧҭը՟ѧӫҸֻػؽڽڲ٩ҝϙ˗ˡΰӻڻعخӠΛˤЧѯѨ͛Πˣ̗͒əǑʚʙɖɒəɖɗ˘ɖȘɛ˛ʙȨe^igakh_VXYZ]a\]P^V^YR\^TWVUXPQXURWTWWYUWWUXWRS^XRUOSPRXPOWR[\W`c[^bca`XUSYZRWZQUTXSPSYW]\S]VVZSRPUNWW]`VSP\YST_^]\_`aaZ\[]][^ae\_bY`Y^d_cca_S\XZ_e^e]_dba`f^Y]b`ddkbbf]_Yeefhg`cddejZeag^jnjgdk`ak`j]hedbahfibllihecfgeemllljniqlheeiihemgipheenginglcnjrlqrfpniuunpkkiotknpvlsinotovniikqsrouzppljmpnsvklprnuroslmknlrivvmpumymnyhhspkrmloumhqusrtsttuusxjorsrumrwptykqp~rormvpqrvyrnqpqlkjwltostvrpwrltksvmswuxxzystjnmtrrqpnor~ouskomwtwwtxvxl|uuyyy|mztwyzmpmsmunxyywz}ƁƆƋɓȏȔȣʨͨϪѪѪЧ̠ͥΚ̤̪ͨФ̚ɗɕȌɌǍȓɎɔȖȒʎȑɕɍɆɍȌǕɝɟ͢˥ˠˣ̞̦ΧͨΪͬϪЩέбҷӷҶճѷѶѴҹչѻӵҷѶѴϴѴҶѮήЭΥ̗ʙ˕ʇƋȍɍȋȔʍǍɉȋƏ˖̚˞ϡѪџϙ˒ɍʍɏˑˎɑˢΜ̛Ι̗˓˒˛ˠϙ̗̒˙͛˙ɖʙʠ˖ʘəɗ˛˜͚̗͜˜˛ʜʬ\\`]W^WS[YXQMMPPU\SQOSOISXZQROVOUPWTTVQPTLQMUSPHOPOPPLVSRQTWUV_e\X]XWUPTTZUUPSKRTSUNQUNNJMZMNUMVQKPVLMPTUVWWNKVSW^V[`UVPU]VW[]_TX_]J]\]QYX^UWX`_\[^^W[bcZ\_W[^^c[^a[][`c\cd`]R[dd\_c]]\]S[`__]W\^Zh`[^hb`cde_XZc__``dk[fkhg_edadbcdnedeX`_gjdemhfehgbeomshlh`glgmopbpjgwmgtgmflgjmmfhlgdufnlnwprjkqllmkiynagmltknlmhtssplqisughnhenqnoqnolnplmnlgjnointvndlritvnjrofpppkisqtrqljjnsjqninqollodkkdkigoqrilinlpnsleirmyubjushjsskuvkikkonumjmtmsiuxsglljrlliljlouunniqsutxptkzÄljǒȐɈə˥̭ͫͩФ̜˞˟ˤ̧̫̬̥̙ͨɜˍȒȓǑǗDžNjǓɍɔˑɒȕɈƈŌǗ˝ˤͨ˩˩ͪ˩̥̥ͦΫϪϫϪ̬ήҳѶֳӷԹйѷҳѵѷӹҷӵҴ϶ѶгаЮѮѪΡ̠̓ʋƉɋȉLJnjɉƂljƉɋɊɐʑˋˈljʈȊƊƎʌ˒ˆʇnjƎɍɓˌNjʐȍɖɖɑɍɓɒˌʍɎʜˠ̡̝̙̜̣͜΢̡˛˟ˣʮkie]\Xf[]T^UT^V[YWYSWYTRQUST\\PZMLO[\XWXNLQTXQ[URVOMLOXYPWORXXTXX^UYOXQUS_XQQWZSOUSQYUX_`]VZ[WPTW][ZTRRVR\\WYUgY[]X]Yc_b[Z\YZZ[^R]bX\_abaW[\]\`^_`][]^[c\_Y\_`c_]`le]be_af`fbb__Z]ejjeaee^jef]g_eg_fdfbadfiafhjfdghihrhdjpnbfjegbcjimhokljdgieidllkghiegmrnqnllipryhjsrlkhtklmkdcmqkrmutsxurrxxnkpmstxpptlrmqkzusmufspmurkppuqmvyiomnlkmmuqrkoiimhsltlkoxsvqrrtkinwsjokusyrrvqtoroopqzjjiiouuwwllurhspvfpnnoxqpqpkrprwvvyrmtmqvlvzmomnonlrqp}jgryqsuymnmpolkwouxtl|~vs|ozywĎĔȗǗȑɛʦˬϮέ̩ʣʡɨͬͮ˯бЮ̪̥ʤɞʙȚɘ˞ɒƒƙƙ˚ɘʚɍʍƒǕƞˠ˩̪έή̭̮ͭͮͯͮέϬѫͱеѷкѸѶѺԻԹҽѻѻѹѷӺҶӺѸηжβΰϮЩΣ˙ɝɓƎNJƉLjɉǎȊǍŎNjǐƌnjȋɌȎƒƎŒdžƏɌʍˍɌɓʍǏƏǒȒɒɜʐǖ˚ɐƔŕǖɔɟ̞̟ʣɠɣʨͤ͠ά̭̯˶_[Y``WRVV]WMSXNPOW\V[XhVOTSYUTXSRRTOUOQU[NSTPRXUXSKROQTWZXXXQSYXR`SITSPPUPURSPJPSRRWUVTST\PWRTZVVWSORVTV`V\`U[ZWXOZVQVQZ[ZUX_VY\_\_R`^]bXVZ_Zec]]\`_d^^`b[Z^e^ZY^_ace][^U]`_\f_ecbbc[__d`dafge]b`m]`edab\`fakclefigdcabiflgdfgakked`ajhgppgdh`melkmiebilligjadhcigiklmqemujmimdkimnmhpsijioqlotiqonjwppqssnkkmjmmjpoonpkumqphhoqjrpehqipnsulhnjglghknnkrmqmrgovwjpvsprpqrrposppipmlicfouojtiqhqrqfmoruqkpvumklrrurvkmkqtyojqpnwutjorijjupntqlorpqjvnlonxstmruqvvvwxnstpt|rw}Ɔɐʖɗǜȡʦ̮ѮҭѩѪͫ˪̭έϭѮίѯΧͥ˝ˡʟ̤̠˘ɔȕȖȒɖɗɗɎƒʜˢˣ˪ͭϭаѮаѭαέϮЭήѰϱѴҹӻӻҹԻѻѷӻռֻӼӸӹѹѷӶҶҶѴѵϱήϫΦ̝ΖʒƑNjņŅNjɊƍƋɋʐʌɑȎɎʌˍʒʕɗʋNJɌɓˑˊˑɑɕǐʌːɖ˓˚̚˔əǘʞ˞̢͠͡Χͧ˧̦ΨͫΰЯγθ^WR][a[UXZSGV`NVUQTPUUTROTZUUWPVPOUVNNXSQWNUPNPQSRRRMQSRURWLYKSTRUBeNNOOMPORQMLRXOOSS^MUUONRRLRMVRQCKNTTTROWYURU_]RRSPVW\T\\R[QX\UbXYX[X]W_]YXS_bYWUe_TZS]Z]\XdZ\_`[`_WZ^^[i_\Y^_[\d\Zgdcg_]^ci^_db_faZaaccdXY_ga`dfdeabbXeg^adcd`febegfchehfhdhf`_eeafhhgehdkcfgecgemjdrjgifkjijijjmrgtrjpjljnuprkkgktjmghskqjkiojrodofhkiilfbbsmkkinkmllidjgolnfnumktkirulhinjlkjqkjeursriqqsopmrkoerruonqpommnohoolphcpnkjojiioljkjpqegjstkforojlkjpqglkhgkurcrlkmfqrkjljrvpvonswfmspuqruÇņǔȖəɠʬ̪ͭͯͭͪˬ̮ЯѮЫ̰Ю̰ЭϮΨΫͥɞʝǖƖǐǒǘɜȜʝɜȖʞʟʨͭέ̯ͯϱϯббЯϲϰ̯ίгеθиѺҼԻԻӺӻһϹҺӻӻֻѻӶѴѶзѻѸѳѲϪ̤ˠʓʉƇdžȄƆĆŌŎƌNJȍɒɎǎƈŌĉƑǎƍǐǔnjƈƎɌɏǖʒɍȗɕɚɛɜʛ˞ʚɜɜ˞Ȝʡ̤ʨʭ̮ϭάγϱж˸[]WYjZUPUVOFPO^WURSVNRVTSQR\RVMPPPWPPRXSKJLQWSPXUSTUPRVWQQQKSVPGISOQJTPOKOPOSMRRLRLSTQSXTNQOTOXPTUSZPRVXSSSTVVUXMRROTYYPUSRTQOYY[\_a\V[^]XZTXWZX`[__]b^`TWZ\][[\\OV^_b`^^_b\W\a\b`Y`]^YY_YbY]X``Wcdg^^`b^`ahc_]bd]jgh`b]^celj_e_]kheifeedegfdjlifdf`cghld_edgjckdegldfipolekdqosgklokeessptlfmloosuimhnjejjmmlmnie`oholhgm_mihjbgnfhhrniggbllknokmsfjjmlhgrf`ourlrqloswouqfjgopfgpglmjkkmpospgqosliooihmpqueojfpkkjikijmhnlurnmmoqomlhhrpphkpqqplrymmfokgnejpjlpnwyusxtxuyzĄŅŃŋƖțǧʬαаͮͫͮͯͰΰαϭѳѲαѰвά̪̤ɡɝɖǓřǗǛɠʨ̦Π˟˟ʤʪͮѵѶѵбʹϴϱβΰ̱϶ҶзжѸѹһջӻԿֻԼӽҼѹӼѽҼӼѻϺѶѵҶѵеεήάάϛʕƑƐȌȎƋƌƈdžȃƅǓǓȓȈdžȈǒǍNJǒɏȖɐȕ˒ȗʒ˗Ǘɗɞ˜˛ʚɟəǞʘ˟ɣʟʤ˦̮ͯίͯͲжѵйλe^][VSV[TWWT]YPRSZS[WXXUYSQYYTQUQQSPLTZPLNOQORTMVOTSOOMPPSVIPOUVXTNKLTVRSWUSIFHKY[XURMJJPU[\ZSRNTSSPRNXRR\cWY[TX]XWX][WSQTS_]]bT[UZSXUc][W[[X^^X]WYYWX^Z`e\UY_\\[]a^fe]]f``ddW[_]\a]____]fdba_\g[bgYca^Zb^cf`bahe__hgd`dc^hjfd_efhgjdZbjm_eeeaijfomkdifffegkelhjfhhokhgjgdklmhpspfkklhnjmseiklloknlgjlposhfluurjrlrikhtikaiahqeuoekggltmqiksjhjgclolmkkqokorujiimdorsqefiriiqqjihkooswshibqlsnrrqmjdqrmurmqellojupwimlfkgultovpkjtmooppqujmnkqionkxmkwrrnlhknwlglsnqustvss{ƆƊƐƛʠɨ˯Ͱϲϰг̱ͱϲϴѴбδеѶҳѰ̰Ѯάˤ˛əǚɞȟɤǠ˭̫ͮϱаϳϳѸѷѴ϶ϵѷӸϴегг϶ӷѹѺҹҺѹѽӻԽֻջֽֿҽоѽӽӼ׽ռռѻѻѻζδѱѭѥ͛ʗǒƗɘɌȓǒȐɉnjƉŕɑȋǒʋ˒ǑǓǘɖʖǒ˛˗˚əʛ˝˚əȗ˞ˢ̟͞ʜʠɢˢˤ̥̥Ϊ̱αвϳϴзһѾѾ__]`RSPRRRVZPZ]LTVVUW\MXSWS[\RZXVVOVRSZUSTNOYPQXKSOQYOQYSSWPRRWVPVZ\OPZUPRPQQLUMMVNLRRRLPXUWPRVSKYRM[]UWWc[R_[]UNVRYSY\[XZWVSSVYZZ]]^]_\fd^YSY]`WWb\Y]`WV\_b`Y[]\]_`\^a]_\Xce^b_`a_]``ceXXhege]f\_ad^dff_d]dacehi^kfckigj_ll_bbdkfjkkibfeidbnjhek_jgbbdeeljlmbeigclmmkifmgljeljlgmmolmrnhmhgtrlokqqlgsoorffoojpqk{isprltjil`hkjdkriecfhdiknwmihhjhpnninhgmimjnjgllrrqseqmopxwjevrntrquujspqpveqmpjpfpkflklchlllrwgklplnqslxnoqjkjnxowukonrpkgtmilrsvwtnjhwvrvvuptrpvpoutst~ÎƐǔǞɦ̪̯̮ΰϳͲ϶ӶӹѵѵϱждҷѶұαίͭΪ̜ɟǤȪ̬Ϋʨˮήа϶ѹллӺӹҸѸѷиѶҶҷӴϲιӴҺһӽԻӾԾԼӿԽ־ֿԿֿӽӻӿֽԼӻֶֽϷѶѳΩϣ͗˙ɔɔǔǏɐƋƈNJljǘǒɏĉƉƉȓȗȔ˘ɕʚɜǒȏʝ˟̟͟ˠ̞˞ˠ̞̜ˢˣʞɧ˨̦̩̪̬ΰѳ϶ѷҹѼӽdWTRRRSU`[VRWYJXRP_SWVTXZ]UPOLSQSOMVNPSOMURLNRNRHOTTOOKNSXPQGURNKLOOQKQNLNLLTMPPUQOROMKRXWPRNSLNOTKPRUPOOVPWW[RTXTSXO[[TUMQZUWRXMX[]Y\PX[Y`SXW]S\X\QWZac^W`PQ[UZYU\Z_ZdcYVT\RXV[__Wcdb\c_]^`Z`]`g^b``\\^beecYb``\jbha\eb_a`ej_`_d_ecifdecbc_age^_aje_gaickegccbedaefjlficdgelhgjnugij`ilqoqligjrmnpigahdijirhdrgiiicbdlkmekhebegeelhdivhkkmhhfogecjkuilsikfrkjkttpgcgjsomoqolngllkhmkjjdghokhjlloqahdkokphlmolqhjpjbbilnlsi`iiorjkhkouoogsnigmikkqvlvwpmmprmjnormrntupkhnt{yƒƙǡɩ˭̭ͲϱγʹͳѲѳҴӷѵѳϳзѳвЯҰҮή̪˨ɩˬ̫ήΰ̰ͲδλչӻԺռּҽӻѸҶдӳѶӵӸйѷҺѻҺӻԽԽտԽսֽ׾־׾վӼӾּԼԿԹԺӷεβΪ͢ʖɍƍɐʕəǍȈƇŊƋʑɉɋnjyŠǎȌƍɆǑ˚˜ʘʙ˙ɞΞ˞̣̚ʢ˜˝˜˜̜̤ʦͤˤɩ̮ήͯϱгҷҺһӸѹϾa`X]SZXRXZ]SVPUSPUXSRR_]X[PPQZ[WRPQSQPRSQHHGMQRRJIOLYRQGKPZLQRHMPKMNLLILTNVUNSPRTTLLMZXOPLVPWZGOSPTWUSXZRWQYV[RTSQQQNLTSTQVVOQPXTTRaS]SPSRY\RXY^XWW\W]j[^ZUZ[T_\UZ^^c]Y\Y^`[YZY[\]`][_i_aaZd[Ve`e]YV_`b^_ehhdf^\Zacbgdb^bkdpjife\f``cgX``[c]^illgfihe`g_cgcggfhghgbiqsmdbigdbfjkekfddgiligjmniegjdlillmhkgnijrlhcelggaggtgdlecedeifgjhnnmmggehjnjegkbgfid_jmsciklkglnnfgpkoppqjtpfhgghklfmnqonkkklofeoijrjiokjmglpjngpntmdkiqqfjnkjwnfepnmnlirljhltuksenjukmlnvm|vmvtplvyĀƃǒǙǝȞˠʨ̴̭ͯѵϵѶҵѷҵҶѴӶӹѷѶѶѴѶееб̮̮̱̰ͬаͱδηӼԼӻҽԽջռԼԻӼԷҶѶҶзлһּտսԼѼѽּֿԽӾֻֽԾԾռ־ֻӻԹҷѱЯ̜ͦ̔ɔɕƔȔɋƐƎȌɉȅdžǎljƌƉNJȆǐǎɍǍ˘ʙʠ̢ͤͦ͠Τ̡ͤˤ̢̣͟ˡˢ̢ˤ̤̦ͩͫͮЮϮγѲҷӶӷξlj[[YQMUXWXR]USLSJOU[]\V]Z\WYTXSPOKTVOWTQPLQOQNMLPJNLMPGVPRSNCESQVOKGMYPWOULMNONNSPOMMWUNROPQJPOORLO[ROQMJYV]TOWGUNUVPYUPPPOUVcVRPUU[\MVNQXXSM[V^OU\RXWSTUVZZ]Z^\SY__\_aa]`[QVXW`^_`_[ac`\\a[gb]_`ZY`^bY^b]_bd][`e_`aaa_de]ad]Wbfjabh]eifcfeedjd[bhgeaefngbhhcglgcl`cc^a]ejfjn`jndhdnjjkjcgimjghjdkh`fokgqgeohfmoemkpnekdfj^aljghslefefahjhk_aikeaoiajfjmijmhfgijqjlqejbeiegpolmflrnfkejhopjogiihhejk`kjpoihkilved`ikcpvqjgkjhdgjmeifieerjmjrehjgljmlgoklpntloumhmilpvtv|ŋƔǝʡɠɧˤ˩ˮͰϰгжҶҸҶѷѶҶԶӸѶҸҶӶѶҴӶӵвѴгѱѲѴѶѻӻӼѽԼսԻվֽվԼԺԺԼӸҸѻѻѽԼտ־ֽֿֿ׿׾ؿֿտԿ־־׾ֻӷѷӱѮѦ͘͝ʕȖǓʓǓNJǎɊNJŅŊņNJȌȅȉɋǍƌɒʑʒ˖ʙ̝ˣ̥̰ЫΪ̧ͦͤΦΪΤˤˡˤͥͦ͢ϩΪͫͬίήѰαѱͻhd]UOUS[VYWQY\WRWWZWORXc_aYVXRQPSPUUSUSQXRRTJRUQOMESMQQHKLPLRLSXRPMNRQMNTSJKNUROMNHMTKWQRHLMTPLVVMQQNLORXNSONRQRROMKNZRNTPSOLTXSSPVLYQSX]\V[Z[]ZW__hZXWMXYYZ\SN_QaW[Z_P\ZPT__X_]`Y][]\^eW^\__^`^d`X\ZabfcbRZ\]^]ac_]_ac`bgc`^d_d_hafb_kedbd`d`ggdZacqdfhciebjehehddZiefifnckjbhekhechcsldjicoliiqeijloplqjioglignkjjkd`]ifgbsjhjfilhubcfjljjehilghdgijgeelljmrrmofdlgoshero_jmjfki_dhqokjhjnmkdletljdgelknimkejieqjhldljibjlklmeifjketh`erkiorgiimrnhkgnulsljp~ythhqsuuwÄÍȖʝɣʥɧ˩̬˯ͭϰдϷ϶ҶзӺչջӺԹӹѷѸӷҸӷѸѸҷѶѷѶѷӻѺѼӻӻӻԽֿ׾ԻԼԸӻһԻսֽӽվؾԽռӾ־տҿԽսֶֽӶԵϮϦ̠˟̛˜˙ʏǑȋȌŋƇƋɎʉƉƇĆĈȌNjǕʕːƌƕǝʡ˨ͫαүѫ̧̦̦̥̤ͨΩΥ˨̢̡̧̧̤̥ͬά̨ͩ˫ͮɼh]_USQYWYWWWYURUSZ\^[XYechekeaXXSRU^`ZWVSVMJSSNLMOHNPMHI[A}LLMVOKPMLKMMSHQQQMOPMPKPKJNPLQXROSLHURLSRVRMMMUKNOOPNMTNQRMQOXOOQQYPMQYRLNRQS]SPRLVY]\MXV]XXWWXVOYWXM[ZZ_X[QYV\_VU[WXQ\`V\YTY\^ae_]\\`a]\``Z``eacace[b`[fh``\^^^_`hdf_dja]ieabd_^bfj_`[cia_^b_ba\`g`dlkimjfjmpjf`heqa`emhkilimjddggcmbecbjifbheeddpjmnfjimgf_g_jed`cjmhefckm`gdimeadifnbih`cfbmflklkjekjeiedchijiibccikpmikjsjclhfhhjdigjjeoj`bfaklhlliftgitmmlkks^dikgqkljli_qhlrdrqcijnrnweuoivtltpgmutllolo{ÏǙɧȨɪˮ̬ʪ˭ˬ˲ϴ̶ζѴиѺҺӻӻӼԻκѻѻѻӶѺԺӻӹθλѷϹӺӻӾսϻνҽӼӽּԽԼоϼһӻҼԻӿֿӾֿ־ӿӿ׾տӼӽҺԶкӶӵѱΪ̤̟˜˚ɚȕǏƐƊNjƊđƊƇNJƊ†ÈĈĊƏĎƐǑǜɟʦ̪Ϊ̯έϰΫ̪̣ͧΡ̠ˠ̣̪Σʠɝɤ˥ʪ̤ͧ͡˩ʪ˪ǼdkmW_WWX__Z]Z\RWPZR]V_oolpqggaaedg[cXYPTPOUMPMHLKINOJOMNPNOHMMKIMQOPKLJLLMUUOOONKMPISEJIJONHRJNLRKTRNRPOKRSOJRRKPROQNUTRNMMKQPSSRULU^UR\SXQSPXTP[]UQOY[WT]RPNT\XVZ^][UUXXZ[_]\\`Uda_`^[Si]]_\laed[Xb_]fZ^\\\^V_^b\]g`^ddhh_[bd^cbf^e^]gefgec\]f`abhb`c]fa``fda\endmeekrd`i``h`ghkjedagigffmjpmrfjjgcejkkpigecidcjkeejdeddbfedccjdcikhhfgchgsidbjcekgi`ab`ehijfdbii`ldfie`eheoklodikjcgoroehhtmmnoefhfghgbmpdilipiifdeejknlmdfhhmkldpinfebhuqkplimmjlupoolcemqkfomsfltvjĄƎȞ˧̩ͩɭˮέˮЮͳҵѶѷѹһѺպԻӼӻԼԻѻнӻӻԷӺӽսӼѻӻӻԻԼֻսԾӼӽռջԽԾսԼվտ־ֽսֿؿھֽֿ׽ؽԽػӵҵҶѵѰժΧ̡̜ͨ͡˜ɛʓɑȓɗʘǓʍNJƆƄŋƅǐǚɕʖǝʠˤ˪ͰήέϱѯϭΪѣΤ̠ͣˡ˨ͪΪ΢̠͡˞ˤ̥̟ʢʣ̪ͨǾXVVPZZ\W\]^\\VXT`TY^e[jqssnrohijejeaX`ONKNDIJNLQEGHMLFGKMCGHLPNMIFMM@JLNINEKIMIEHJJROEPKOHOPDGGLJRMOLKSHIPTGNMMJVNOXROLOKQRSQTJQSIL]PKTNMQQXLFMOPSSRZ[WNSPTbXY\UXVU\QSX\WVTQRR_[XMYVSWZ][YW]Y^``ZdW][^[[bba]\X\M\`f\]_bU\]S`d\a^_YV`dR_`e]alge\[]Z\^b]ce]cgeaeinfba`bkeelcXal_diedc`\`memgfdga_egfhdabddeifc`bfcbaaeia`g_cd^]ac`fcc_nffeeffjgdb`agheacch_hk^de_foil`dab`bY^bbegolnljgofjfehhifb[e`chfldflhge_jdb^dbidhl_idgemnlfabee`fdcknskcgdehmsrmjlmyjd\nilhlkhmosm|Ì×Ǥɥʩ̪ˮЩήͱ̰ͱ̳ϵеԵӺѸҹӽӽӽӹѹӽӼӻҼԽӽҺӻӻӻӻӸӼѻѻӹӻһԼԽԽҽӽӼԼӼԾստտվֽֿԿտӽӿսԻһҶѶйѶдӫάͫΦ̥̤ˡ˝șəʜʗəɕɐƈ|ăŅŊÇƖɓɗǝʠͪέΰѱαγѲϰϪ̢ͪͣΤɥ˧̧̤ͤ͠˝ʞɠʡ˝ʝɠˢ˫þh^`]\W]]f]bh_Z_[]`c\__quu}z}qwqoneifo^UUJNQOVMNPOJNQINYPGHLLOPUQLJIHGKPROPELLLHORKOMIKIKNPJLH@VGKMUGHKNPNPNJPKNNPINLSXNNPPVSURQORTOL\YXVRMOMXOMXXYPWP\X[T]ZXQPUTY`\XXLOTWYRMNWXW[ZPX`\R_Xa\ZY]ad[dZ\\\`Y]X_`c\_Y_\[\\`_^e]Wf_ag_^gbe]]f`ef_e`abel`\^[`fagZ_`hdjfcjdh``]fsgekhfe`mledeaebdiijkeflh\h]oidcd\bbadgdaidajadee`f]ci`dh_ecemjgohdhhdbmfmd][efqdkjdmj]hmlcdefhijeifjmiocilidhekpgb_iikcehjop`e\grqgblknfhdelljr^geaegfnjffhfgjjsfkpfkhejkkrmmlnodfktpllhhgkmoqw‚Ěǣʧʩʪ˫˯ͮαбϳγε͹ѺһӻӻԼӻҼѹӽҺҽӼվվտӾҽҽѽνӽԽԻӽӽѻѼϽӼԽֻԻһӾӿؿֿֿ־տֻӽӻӼӸӺϺѺѵЮͮͬΨΣΤˢˡɢ̡̞ʗ˕ʈƎNJÐŌċÌƕȗʚɥ̮ˮͪαгѴѴӻҴγα̧̫̭ͨΤ̡˨˥̧ʠ˝ʟˣ̠͝ʞɥʪ¿\X^Ud[[g]]jml^]_eXd^khun|{{~z|u_iaaaSLILKTSRQPUJKDFNLGSOORPPOTQXHIMOMOKMOPNQRQRIJKOLIMLLNLNQONGKFHJHSPRNKUPRNNMPLMQRNVNTRUNMMOR[TUXR^QWSPWXSXZX\W\XaWXPY]YUaUQX][WSVZT[V`Y\YWS\Y\_X\_X^\ffaX`Y`b_\c_c\ZY\\cbd_^[ZZdijhbagd_``bj]hbae`bbc__c`caf`ea`d^cbdibkgleemcjdihllfjedjhgeimomm_`faagfrhhghdilhdf_g`fljkihfded_iaaeiYZdhfkfdhqehggkjhifaejfmjcnfbdmdcf`ijddlnogldpgn_hj_kpkifiiicggjnigofhikiqgmemjnsgeglkrifeimeeajf^gmmgljjmgrkemloekjegurlpnignrlvuntsrsrsmsxÄŕȣ˦̮ͧͪˮͱͰͱб϶елԻҽӽӽԼӽѻԼֽԽӽӼӽҽԽӽӽվҿӿԽӽӽջսսսӽӽԾվԿؾؾֽ־տֽֿԿҽռӽҺԽּշе̤ͯͧͥ˧˧˦̢̡̞ːȊʼnƌƆďƚƘǕʚɝǦ̪ΫΰϲιѶҵӶѵѳҰѱ̳ϲΩΨ̢̩̥̤̥̜ͪͤ˜Ȝˠʥ˨Z^SVXTY`fimin_]e\dgolpvx~znoim\WQIOLSQKOFJIFELIEJKKJJEIKLQPKHLILHBIOKLNIGJFLJCONLHFCHJLHONLGKENNMOMOPMDMHINOMNNRNMRSSMOOONJRR]NKLQNQSSPCMWOY[XTOQQVQZSSUQJUZcVP[OORWVWW\_XQ]\SZ^YY[_`XQb]YV\VZYW_^]^[S]T\g``Vc`_`_Xfbc\\^bba]`[b_]_Yb`Z^\`b]ihge^__f`ekjecf`dfg_]ghfff`l_dnddcmfcahbe`[]lii^bb^a`ibebcZ`ffcpb^]b]_bgaf_]`b_i_dh`_fbaacagde`gjecea]fefghjhi_gbddfjgfeeieeffjgdjdgie`ehecdjioabighgg]eifh``jjlhihe^aj\difjdhhgfipgjgdhgfohhdbghfposlllskjliprienjes‚ÒƝɥ˧˩̭ͯΰа̮ͮϯѳҶԹһԽ־սӻԻӺѺԽӽӼӾսӻջӼӽԽؽԿӻԽԼӻӼӽսֽտԽӿԽ׽׿ռӽԿҽտֿֿսӽջպ׻׸ԶҲѰϮϪ̫ͫΩΩΦ̣˟˙ǏȎNJƑɓʝ˗ɞ̤Τ̨˭ͯѳѶԸӶҶӵӱϯϮββѮϬϨ̨˩˪̡̩̞̟ʛȜʣʤ˪ÿ`_]URX]jioopparrosx{xp}|zrikdZNMHOJPPPPELNHIRKWMDIQCSOTG}OKOKJRRROHHFJNIKLCJNHLOGMPFGVILOMPSNCKSGHNJHGLFLJMRSOPORPSOVLKOMUJKURORTPQ[WWUT[[RUTZRUNTUSSRXXT][RNP^RWO^WV^WS[\XVZPcZXa_k\[\iZ]b]b^__][Waa[[c\\bg[b__b`_ad]^\e_X\^[ji`h``aa\_ehgffhcbebbbjgjigjsocjiplh_cdeijhggmfh]hbcecdec_i`ejfij`e\hkhefff^e^c]klc]_c]gaeh]cgkecigchbdegdeigemfdhimjbfjifjfhjedmbfhgb]dl`cdjikghfcejsmfhcdhmfjjdjdidgflkbdgjif`cfjecefildcaljcflnkkokjcgjsihmssljnojpjnmmmtjldikr~ÍŘǣʩ˭̮ͱέͬΩάα̳ͶҹһӽӽӺѼӽԻҽѽӼӽӾսԽӾӽӼӽԿԿӽվԾӾӼҽӽԽԾտ׾ֿӿտԾ־־ֽԽֽսҸѶѵѲѲдβίήή̞ͪͥʝʙǖƚǜəȗʝˣʩ˱ͱʹεжҺѻӺкӳ϶ζδϵϲѬϰΧ̩˪˪̪ʪ˧̥˨̨ˬˬ^ZPY]fnid^osv}vxu{{||{xyoodVVQOJHGNMMHHPLEOHSPNSGLPSQIRRQIPPGIMJVOJLIGPHNPZNKHIGNRREIJGJEJPDGHEOORKMOMQHJLPQNPPHOULOVQU_KNQSXPMPM[QURRPRVQOTX]XRRIYOURSY]PU\UPSSX]XW]]`\Zc\[[XYb]_Y`\[cgdfc^a`]d`\a_^__g__a]`Yedab]ad\_a^d^`c_ace_d`fcafdba`gabb`bghegjjdcektkiikimjYdlid`nic`gjddcehc^eggehcb^hfcecfhfeddajaal\e`\]aejacgibefdghbddcgbdccfefgdj``ccdbdgdchgdfiggcahpcf`a_iqnejjfhgnhijdfiiidcegpf_lieikia`gkjnminaiiilhe``ibnjkmipromhnqjinjpqmghoulssviplrizŗǛɨ̭ήͰΪ̨̦̤̦̮εйѼѻӽӽԼѻӼսԿӽӻӻӻԼվѾӾҿֿԿԾռӽԾտԿԿտԾӿ׽ֽ׼ֽԼѺѺѺѶҸѶѶѳίέͪͣˠ̢ˠ˟ˡ˛˙ǚʤ˱ΰϴҴҸиѷѶкѹѻӹεзѷжβбίί̮̰˱ʱ̬ͭͫά̰ͰfW]a`^eoibpsvxzytng^WNMFMFQFMNUJLIQJMSIMLDOMSNJRQRQIOJNPMOPIGDGLKGHPRKFFJHLFRGMHIGNRMNLSIQHFGSQFNHKQPSWKROMLNMRRPNNQPQROXOSOQOWQX[JSNQLQTVQUPWSQXZSXNQQW\WZ_]bY_WYXVWX]\W_`a`aa\_a[Zdf`ZZ_]\ba_V^a]bifdd]\fcfa`bd^Z^i]bfbbc\ad_gcffd^abfaafg^jkimlfm``mgcbhdggbc__f`ba`jdaa__^eadhbfdd^dgfhdcdjfc\a\Xbcdd_f`hdgigcechbda^^bbhb[acacfagbck_bf_cchgakee`c_bcikegfed`fokmrred`kifcfc[`dihlbjfjbifdchldleg`dnaihgbfmfmhfgi`mkklmklafirfgjkgeiioujnlelktwx~ÕǙəʞɫϰҲѫ̦ʞɗȜɦ̱ϵѹһӻսսӽӻӻԽӾվԿҽԽսսӽؽӿӿӽӽտտֿ׿ֿԽּ׻ԾսӼӺӽӹӻѺѻѶҳүЫΫϫΩΧ̣ͣ΢ˢ̤̪ΰвαβѳҸӺѷӷѺҺӷѺӸӶӶҶгѳϲҵѵұеѲ̲α͵гдS\Wghrhmfsqpnwx‡~rhWVTFGHIDDFIFIQISJNLNLQHMGKLQHILNMLJDHIJKLIH~LLHGIJKGPHDFC@JKIPLSCKDIKKKMERIFEOPSPLFMNKNMUONRJSUFO\JKLSJLSRPUQHPLRROWNOPNUTVZTNPNQT_OZ]WOWSQ\_\WQR`U_[Xb[\\\ade_i\YXdfe\^g\WY\]\_d`\f_^XYedX^W\`]e]gideb]chia_fe[ehgegabecifjeonjpmjiklijbdffeed_bef\ccfkhe``eegdjebcealfb]___deac_^eb__Zdda_`_Xjg`ga^d]]^`cac\bkge`cfjhgl^`icd^adjc]dnbddd`bcadlnddl`{shgkccjc_jkijc`jbddebkdimldajmj_`g`\`bbakgedggdqghffjdhhutjmemkougjgjmnrkjpovqoǡ˞ɟȬͲаЭͧʡɠɞɧ˯ʹѶѷӻԽսսӼԼսӾջԿѽӽӿӿԽӿԾ־ӽӽӿֿֿԿֿԾӹԻӼԽӽӽԽսռӺҲѲЮͰαѬϡ͢ΪΪ˧ͫͭдҲбѴѷӸӶҺһԹյӷӵѺҶѴгѴӱвҷѻҷѶѸѶѷҵѷжT_eefdi]irprxr~|~ytjbLKIFDJPFGTMHKKOGKKKLMFEGCHOMMJGGFJHMPGJMHCIGOL>AAMGMLSKLLBIPLMIHLLEACJMNANMRJJJQPHHKFOTMOOJEOMJSMSNOTRIWOTVQVJLNIOQRXXNSSS\Y\QXVXXNXONXR[Y\\NPN[XXc_ZY]b`^feggdhccbc_`^ca]h]^_Zc`U_[^Xe`^a][\]`W^_Y_^cZZicgikhdee_a^hhjedeqmrxqghjemjeih]brak]]agdgca_ghafe\d\__dlhaa^fffdca\gc\_e_gb`_]Wcaaaiddi`^abcaeacddac`bXclilh^_X^ddb`d_ddhibbfp^fihfkfebca^feilkbbc`kfidkbc^aibgeeelhhhl^ledaaegnaefaefcfgjuehdjdkeiuummkllkmieklm`olvikpwÓǙ˜ˮϵҰѮΩ̡ɝʛɢˬίͲηѷһһռԽԽֿռӻӽӿս־ӾӾҿӽҽֽԽվֿҾ־տսվԽԿֽؿּջսҼӽӽս־վ־ӽӻӷҷҳѶӱѨϨ̫ͭабеӴӳҲγѳѹӺԶѹѷйҷӻӸҲѱѳѲдѶжѺѺӶӷѸѼӸѻӹ__\Xf^dkijpxs|y}ql^PMQQPMIB}JMMQLGOFJHCIRLKRMNLICKLKMJEFLGGIHIJNIHGF~LOGFRHHILGHMMGJMPNQJKPJ\HKDNMLFJHLMLHMKQQRPOXXUSGRLOOSQSQPRQVOTZYTRMKTYRXW[SPZUXQWUPYRR\NV\XQSRWSZR\YVW\_hljdimicakkogbjfih[`]Y`_bX^^]fa]`^_X_Y^e_\e`diellfblkhefaa_c_dfdkmliklwmqljhfcifdmii_e`lpfce``^``fkebjchbbcaefg`Xd_ahYf_a]`eaeb_`de_]]]eefj_e`edb`^a`^ead`__dhcZ^acba]gdei_nhjdifejeeddiifanbffmgh\\djc_^`g`dcadhdb]el``d_hfedej`gfifhgiheedeitrecdgimafj_kkjedflljpkomsnl|ƋȞɦ̨ΫѫΡʜɝʝǟ˨άѳзѹһѼӼԼֽؽӾӼֽջսսֽӽӿԾӾӼռֿԽֽԾսӽտ־վֺּּԽҸѸҳѰβ϶еѹӺмӸҵжѴӶӶӷѶѷӷҵѶӲӳҴв̰϶ѷѹҺѻҼԽӾҿӽսӼҼeek][jhhojuxvs|z|yppgcRMNQJPKOOPILKEJIHNDKTNGHOSMF?HGIKJLMLGDKJCPQHHEGRMSGEJCHDNAJLJJSGGHGQMUPMELLLQQILLIHH@KJOQRNHQIMPLPMUYMPRMYTRQYQPO[PQUMWKUUYSVQRXZWZX`_ZVUORSX]Wc\_]XZ]_ddcibjomomkljkjnqkfc^geh_\_a`i^aY]\`^]a`\_c\Y`ihiionqpkibcheje`gfiqpzrupuikdskddafdjf`bi_e[dcehidb_dbeedc_ae\begj]``^acc]h`Zae]__[b``_gagaifW]]c_adb_\`c`ahcii^]`^bep^`djddhi`b\_e]dchi_d_i_gcghng`cdji`b]gdhfeefiddbcbfdckmgeeceeihidheclmgenidgijiillkicggfdfgghmnlglmjiajwĎÖșțɢˣ̚ʒǖƟȣɩ̮ͲιҶҶӼӽҼҾӾԾսֽӾѽѿӽӽӼսӽӿѿ־׾վֿտվվӿԿԾӻչԸѻҷҼҺӹӷռԾ־ҾҼһѴδдϴѴҷѷвϱϪ̪ͬήαйѻпҿҽӿ־iemmeahekhovx}wz}tmjPOPMPBJLQGRMOOPORUJL]PHJPOILNIJOOLGLDIKNJNJNFGEEBJRMCJHHDM?}GGLHNRMMEHKLQTRSOIIQPPRRGMOKLMRPXNUPFMOWQLSOMOKWQRRSTQWOXZUPPOUT[U[NSYR]^ZU_PZaPX^``XX[[X\`aeifjrrj}uopqunownmojib^\[dd_e\gWX_`^]^W_`b_^_ceimix~vw}rnklodifjjmsvwwvvvvvktlmurmdidbe]]gebdedddghcbghjhkahd`dbaiia_mac_f`b_\dbbcdb_c]gfaedfhea`gedcc__`adjd`defbedcchhpbecgifbajid_dedcfjlhlgi^fhgifid]c`e^a__eejajceceafbmlojhqiddfighdd]kkppsubjjneildhiflkionxmlempulqflgƎǑƑƕǞȚʘǗȠȥ˫̯͵ϸҶӺѺӾ־տԿտֽӿ̾ԿվӻԼԽտ־տֽտֽҽӼԼҽӿӽֿؾؾѻӸҴκҶѯаѮͮϨϠɤˬβжӻԽ׿igmrk^dU`_kr}~npupql_NMJQQJOHMMIQQOMVPOJENMPIJIOKJKJFJJHIEDLMMJIGGMIFSEHCHMGSNHGKKJ@@DJHMLONMIKHFLORVJUGJQFJOIIKFKMPRSOLRK[RNKNOJVQSLTQSLMOO\VOPOVWS^ZRTP[T_XWRRMRNPWWX[a[Z_fijppilwy{yvqouqmjfcbc[[][bOf][]cX[adX^`Z[`^]jmst~z{utpjaeglqnikqsysxs}kggpumilhfljdh``beabbeba^c\bcdhcjhidd_dgfmq^]Zde\`X`_]id]b_eabg]dZd`e^`^d]c]afdemf`ehiafgc`bgk`h_ei_c`abbfa_ge\eb^fa`li^bhfdf`_`d`e^kdddieddce_bbjbbaabhbbihemkb\dgi^cfggigrrildegamoinmjrogl`ojpknls{vÄňƜǢǜțǨ˫ͯʹϹһӹлѻԽӾֽӽսսӽֿսӺӽӽҽһտԾտտվӾֿջҼӷгЯϯϬͪΦ̧˫ήϰηϻҽӿֿqqyufa^[ecmuxrhkpmro[OHMMKMSJILLQNIPONQHMLNQSSXPB}CFPAIML|GD}F@KEGJPMHGHIGJH}OJHJHIIMGHGJFNIKNUJHGQMMPQOLQPOGOLQMHRLROXXSLRQPRORNOGPWOMSYZSOOYMTXMWO\UKR[RT^Z[[XMXZN^[NSSSZ_ee`cahoyy{xzxxq|xxse_^][WZU[XYaac`a_bda_abd`^`aj{|~~{tollrolkrorsuxlsrtmjprnujsljfccicZ]fhffkde`]bbelkhcf_`cXdgddglehg]ffeahefd^lc`_dhdea]da]cbid^_babgeahadg_bkedeiggdofc`f`bd`_^fbdgeg_lbgfb\cb`c]af`[__c^hehicdaikki\e^cg`kfjdi]dgqndigccaq`gfhZeemkeljmifgoocvpddjlknnmjery|Øȥ˦ʦɫ̮ͯ͵еѸӺӺһӽҿӿӾֿӿ׾սԽտԽҽҽսռӾӾּֿԽָҴаή˫ήϲбβϷϼӽּ{}ufYY`e]jr|~ywtsrrk^SQHJMMOKUMORKMIHPMPRTPQPMPNOJCFGIJIMGJKGMLLGKPOTLHMGLOOILKKIMOGL