Add a simple 3D APIs demo

Ruslan Kabatsayev b7.10110111 at gmail.com
Fri Aug 19 14:41:48 CDT 2016


This adds a 3d-demo wine application. It will allow users to check that their
system can handle at least basic WGL, D3D8 and D3D9 before they need to look
deeper into their problem.

Signed-off-by: Ruslan Kabatsayev <b7.10110111 at gmail.com>
---
 configure                              |   26 +-
 configure.ac                           |    1 +
 programs/3d-demo/Makefile.in           |   14 +
 programs/3d-demo/common.c              |  107 ++++++
 programs/3d-demo/common.h              |   36 ++
 programs/3d-demo/d3d.c                 |  605 ++++++++++++++++++++++++++++++++
 programs/3d-demo/d3d8.c                |    2 +
 programs/3d-demo/d3d9.c                |    2 +
 programs/3d-demo/demo.rc               |   61 ++++
 programs/3d-demo/main.c                |  175 +++++++++
 programs/3d-demo/resource.h            |   33 ++
 programs/3d-demo/wgl.c                 |  473 +++++++++++++++++++++++++
 programs/3d-demo/winehq_logo_glass.png |  Bin 0 -> 31512 bytes
 13 files changed, 1517 insertions(+), 18 deletions(-)
 create mode 100644 programs/3d-demo/Makefile.in
 create mode 100644 programs/3d-demo/common.c
 create mode 100644 programs/3d-demo/common.h
 create mode 100644 programs/3d-demo/d3d.c
 create mode 100644 programs/3d-demo/d3d8.c
 create mode 100644 programs/3d-demo/d3d9.c
 create mode 100644 programs/3d-demo/demo.rc
 create mode 100644 programs/3d-demo/main.c
 create mode 100644 programs/3d-demo/resource.h
 create mode 100644 programs/3d-demo/wgl.c
 create mode 100644 programs/3d-demo/winehq_logo_glass.png

diff --git a/configure b/configure
index 3eba2d2..efae53e 100755
--- a/configure
+++ b/configure
@@ -787,7 +787,6 @@ infodir
 docdir
 oldincludedir
 includedir
-runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -1451,6 +1450,7 @@ enable_libs_wine
 enable_libs_wpp
 enable_loader
 enable_po
+enable_3d_demo
 enable_arp
 enable_aspnet_regiis
 enable_attrib
@@ -1628,7 +1628,6 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
-runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1881,15 +1880,6 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
-  -runstatedir | --runstatedir | --runstatedi | --runstated \
-  | --runstate | --runstat | --runsta | --runst | --runs \
-  | --run | --ru | --r)
-    ac_prev=runstatedir ;;
-  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
-  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
-  | --run=* | --ru=* | --r=*)
-    runstatedir=$ac_optarg ;;
-
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -2027,7 +2017,7 @@ fi
 for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
 		datadir sysconfdir sharedstatedir localstatedir includedir \
 		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-		libdir localedir mandir runstatedir
+		libdir localedir mandir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -2180,7 +2170,6 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
-  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -6253,7 +6242,7 @@ else
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -6299,7 +6288,7 @@ else
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -6323,7 +6312,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -6368,7 +6357,7 @@ else
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -6392,7 +6381,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -18229,6 +18218,7 @@ wine_fn_config_makefile libs/wine enable_libs_wine clean,implib,install-dev,inst
 wine_fn_config_makefile libs/wpp enable_libs_wpp
 wine_fn_config_makefile loader enable_loader clean,install-lib
 wine_fn_config_makefile po enable_po clean
+wine_fn_config_program 3d-demo enable_3d_demo clean,install,installbin
 wine_fn_config_program arp enable_arp install
 wine_fn_config_program aspnet_regiis enable_aspnet_regiis install
 wine_fn_config_program attrib enable_attrib clean,install
diff --git a/configure.ac b/configure.ac
index 24e5190..9c1ab55 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3459,6 +3459,7 @@ WINE_CONFIG_MAKEFILE([libs/wine],,[clean,implib,install-dev,install-lib])
 WINE_CONFIG_MAKEFILE([libs/wpp])
 WINE_CONFIG_MAKEFILE([loader],,[clean,install-lib])
 WINE_CONFIG_MAKEFILE([po],,[clean])
+WINE_CONFIG_PROGRAM(3d-demo,,[clean,install,installbin])
 WINE_CONFIG_PROGRAM(arp,,[install])
 WINE_CONFIG_PROGRAM(aspnet_regiis,,[install])
 WINE_CONFIG_PROGRAM(attrib,,[clean,install])
diff --git a/programs/3d-demo/Makefile.in b/programs/3d-demo/Makefile.in
new file mode 100644
index 0000000..4ca5b6c
--- /dev/null
+++ b/programs/3d-demo/Makefile.in
@@ -0,0 +1,14 @@
+MODULE    = 3d-demo.exe
+APPMODE   = -mwindows -municode -mno-cygwin
+IMPORTS   = user32 gdi32 gdiplus opengl32 glu32 d3d8 d3d9 d3dx9 ole32 shell32 msvcrt
+
+C_SRCS = \
+         d3d8.c \
+         d3d9.c \
+         wgl.c \
+         main.c \
+         common.c
+
+RC_SRCS = demo.rc
+
+INSTALL_LIB = 3d-demo.exe 3d-demo
diff --git a/programs/3d-demo/common.c b/programs/3d-demo/common.c
new file mode 100644
index 0000000..0551785
--- /dev/null
+++ b/programs/3d-demo/common.c
@@ -0,0 +1,107 @@
+/*
+ * Direct3D 8/9 demo
+ *
+ * Copyright 2016 Ruslan Kabatsayev
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#include <objidl.h>
+#include <gdiplus.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "common.h"
+#include "resource.h"
+
+void fatalError(HINSTANCE hInst, int statusId)
+{
+    WCHAR message[STRING_MAX];
+    WCHAR caption[STRING_MAX];
+    /* Make sure the strings don't extend indefinitely if we fail to load them */
+    message[0]=0;
+    caption[0]=0;
+    LoadStringW(hInst,statusId,message,sizeof message/sizeof message[0]);
+    LoadStringW(hInst,STRING_FATAL_ERROR,caption,sizeof caption/sizeof caption[0]);
+    MessageBoxW(NULL, message, caption, MB_OK|MB_ICONSTOP);
+    ExitProcess(statusId);
+}
+
+
+int readTexture(HINSTANCE hInst, void** bgraBits, UINT* w, UINT* h)
+{
+    static const int pixelSize=4;
+    GpBitmap* bmp;
+    BitmapData data;
+    GpRect imgRect;
+    ULONG_PTR gdiplusToken;
+    int width, height;
+    DWORD dataSize;
+    HRSRC texRes;
+    HGLOBAL hTexRes, hTexData;
+    LPSTREAM stream;
+    LPVOID texResData;
+    GpStatus status;
+
+    struct GdiplusStartupInput gsi={1,NULL,FALSE,FALSE};
+    GdiplusStartup(&gdiplusToken,&gsi,NULL);
+
+    if(!(texRes=FindResourceW(hInst,(LPCWSTR)MAKEINTRESOURCE(IDR_TEXTURE),(LPCWSTR)RT_RCDATA)))
+        return DEMO_STATUS_ERR_TEXTURE_FILE_READ;
+    if(!(hTexRes=LoadResource(hInst,texRes)))
+        return DEMO_STATUS_ERR_TEXTURE_FILE_READ;
+    dataSize=SizeofResource(hInst,texRes);
+    if(!(hTexData=GlobalAlloc(GMEM_MOVEABLE,dataSize)))
+        return DEMO_STATUS_ERR_TEXTURE_FILE_READ;
+    if(!(texResData=GlobalLock(hTexData)))
+        return DEMO_STATUS_ERR_TEXTURE_FILE_READ;
+    memcpy(texResData,LockResource(hTexRes),dataSize);
+    GlobalUnlock(hTexData);
+    if(FAILED(CreateStreamOnHGlobal(hTexData,TRUE,&stream)))
+    {
+        GlobalFree(hTexData);
+        return DEMO_STATUS_ERR_TEXTURE_FILE_READ;
+    }
+    status=GdipCreateBitmapFromStream(stream,&bmp);
+    IStream_Release(stream);
+    if(status!=Ok)
+        return DEMO_STATUS_ERR_TEXTURE_FILE_READ;
+    if(GdipGetImageWidth ((GpImage*)bmp,w) ||
+       GdipGetImageHeight((GpImage*)bmp,h))
+        return DEMO_STATUS_ERR_TEXTURE_IMAGE_SIZE_GETTING;
+    width=*w;
+    height=*h;
+    *bgraBits=malloc(width*height*pixelSize);
+
+    data.Width=width;
+    data.Height=height;
+    data.Stride=data.Width*pixelSize;
+    data.PixelFormat=PixelFormat32bppARGB;
+    data.Scan0=*bgraBits;
+    imgRect.Width=data.Width;
+    imgRect.Height=data.Height;
+    imgRect.X=0;
+    imgRect.Y=0;
+    if(GdipBitmapLockBits(bmp,&imgRect,
+                          ImageLockModeRead|ImageLockModeUserInputBuf,
+                          PixelFormat32bppARGB,&data))
+        return DEMO_STATUS_ERR_TEXTURE_DATA_READING;
+
+    GdipDisposeImage((GpImage*)bmp);
+    GdiplusShutdown(gdiplusToken);
+
+    return DEMO_STATUS_SUCCESS;
+}
diff --git a/programs/3d-demo/common.h b/programs/3d-demo/common.h
new file mode 100644
index 0000000..54479d7
--- /dev/null
+++ b/programs/3d-demo/common.h
@@ -0,0 +1,36 @@
+/*
+ * 3D APIs demo
+ *
+ * Copyright 2016 Ruslan Kabatsayev
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _3D_DEMO_COMMON_H
+#define _3D_DEMO_COMMON_H
+
+#include <windows.h>
+int readTexture(HINSTANCE hInst, void** bgraBits, UINT* width, UINT* height);
+void fatalError(HINSTANCE hInst, int statusId);
+
+extern BOOL vsync;
+extern BOOL setVsyncMode;
+extern BOOL fullscreen;
+extern DWORD fullscreenWidth, fullscreenHeight, fullscreenFreq, fullscreenBits;
+static const int bgRed=85, bgGreen=136, bgBlue=238;
+extern UINT_PTR exitTimerId;
+#define MATH_PI 3.141592653589793238
+
+#endif
diff --git a/programs/3d-demo/d3d.c b/programs/3d-demo/d3d.c
new file mode 100644
index 0000000..92ee4c3
--- /dev/null
+++ b/programs/3d-demo/d3d.c
@@ -0,0 +1,605 @@
+/*
+ * 3D APIs demo
+ *
+ * Copyright 2016 Ruslan Kabatsayev
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "common.h"
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include "resource.h"
+
+#if D3D_VER==8
+#   include <d3d8.h>
+#   define APPEND_VERSION(x)           x##8
+    typedef BYTE                        VertexBufferData;
+    /* Fixup renamed methods and constants */
+#   define IDirect3DDevice8_SetSamplerState    IDirect3DDevice8_SetTextureStageState
+#   define IDirect3DDevice8_SetFVF             IDirect3DDevice8_SetVertexShader
+#   define D3DSAMP_MINFILTER D3DTSS_MINFILTER
+#   define D3DSAMP_MAGFILTER D3DTSS_MAGFILTER
+#   define PresentationInterval FullScreen_PresentationInterval
+#elif D3D_VER==9
+#   include <d3d9.h>
+#   define APPEND_VERSION(x)           x##9
+    typedef void                        VertexBufferData;
+#endif
+
+#define EVALUATE_AND_ATTACH(x,y,z,w) x##y##z##w
+#define ATTACH(x,y,z,w)             EVALUATE_AND_ATTACH(x,y,z,w)
+
+#define Direct3DCreate(x)           APPEND_VERSION(Direct3DCreate)(x)
+typedef APPEND_VERSION(LPDIRECT3D)                 LPDIRECT3D;
+#define ID3D_FUNC(func)             ATTACH(IDirect3D,D3D_VER,_,func)
+typedef APPEND_VERSION(LPDIRECT3DDEVICE)           LPDIRECT3DDEVICE;
+#define ID3D_DEV_FUNC(func)         ATTACH(IDirect3DDevice,D3D_VER,_,func)
+typedef APPEND_VERSION(LPDIRECT3DVERTEXBUFFER)     LPDIRECT3DVERTEXBUFFER;
+#define ID3D_VERT_BUF_FUNC(func)    ATTACH(IDirect3DVertexBuffer,D3D_VER,_,func)
+typedef APPEND_VERSION(LPDIRECT3DINDEXBUFFER)      LPDIRECT3DINDEXBUFFER;
+#define ID3D_IND_BUF_FUNC(func)     ATTACH(IDirect3DIndexBuffer,D3D_VER,_,func)
+typedef APPEND_VERSION(LPDIRECT3DTEXTURE)          LPDIRECT3DTEXTURE;
+#define ID3D_TEX_FUNC(func)         ATTACH(IDirect3DTexture,D3D_VER,_,func)
+typedef APPEND_VERSION(LPDIRECT3DBASETEXTURE)      LPDIRECT3DBASETEXTURE;
+typedef APPEND_VERSION(D3DMATERIAL)                D3DMATERIAL;
+typedef APPEND_VERSION(D3DLIGHT)                   D3DLIGHT;
+
+#if D3D_VER==9
+#define ID3DDEV_CreateTexture(d,w,h,l,u,f,p,t) ID3D_DEV_FUNC(CreateTexture)(d,w,h,l,u,f,p,t,NULL)
+#define ID3DDEV_CreateVertexBuffer(d,l,u,f,p,b) ID3D_DEV_FUNC(CreateVertexBuffer)(d,l,u,f,p,b,NULL)
+#define ID3DDEV_CreateIndexBuffer(d,l,u,f,p,b) ID3D_DEV_FUNC(CreateIndexBuffer)(d,l,u,f,p,b,NULL)
+#define ID3DDEV_SetStreamSource(d,n,sd,s) ID3D_DEV_FUNC(SetStreamSource)(d,n,sd,0,s)
+#define ID3DDEV_DrawIndexedPrimitive(d,t,m,n,s,p) ID3D_DEV_FUNC(DrawIndexedPrimitive)(d,t,0,m,n,s,p)
+#define ID3DDEV_SetIndices(d,b) ID3D_DEV_FUNC(SetIndices)(d,b)
+#define ID3D_GetAdapterModeCount(d,a,f) ID3D_FUNC(GetAdapterModeCount)(d,a,f)
+#define ID3D_EnumAdapterModes(d,a,f,m,dm) ID3D_FUNC(EnumAdapterModes)(d,a,f,m,dm)
+#elif D3D_VER==8
+#define ID3DDEV_CreateTexture(d,w,h,l,u,f,p,t) ID3D_DEV_FUNC(CreateTexture)(d,w,h,l,u,f,p,t)
+#define ID3DDEV_CreateVertexBuffer(d,l,u,f,p,b) ID3D_DEV_FUNC(CreateVertexBuffer)(d,l,u,f,p,b)
+#define ID3DDEV_CreateIndexBuffer(d,l,u,f,p,b) ID3D_DEV_FUNC(CreateIndexBuffer)(d,l,u,f,p,b)
+#define ID3DDEV_SetStreamSource(d,n,sd,s) ID3D_DEV_FUNC(SetStreamSource)(d,n,sd,s)
+#define ID3DDEV_DrawIndexedPrimitive(d,t,m,n,s,p) ID3D_DEV_FUNC(DrawIndexedPrimitive)(d,t,m,n,s,p)
+#define ID3DDEV_SetIndices(d,b) ID3D_DEV_FUNC(SetIndices)(d,b,0)
+#define ID3D_GetAdapterModeCount(d,a,f) ID3D_FUNC(GetAdapterModeCount)(d,a)
+#define ID3D_EnumAdapterModes(d,a,f,m,dm) ID3D_FUNC(EnumAdapterModes)(d,a,m,dm)
+#endif
+
+// Common D3D 8/9 declarations of D3DX matrix functions. Actual library will be d3dx9.dll.
+#define D3DX_PI MATH_PI
+typedef D3DVECTOR D3DXVECTOR3;
+typedef D3DMATRIX D3DXMATRIX;
+D3DXMATRIX* WINAPI D3DXMatrixRotationX(D3DXMATRIX *pout, FLOAT angle);
+D3DXMATRIX* WINAPI D3DXMatrixRotationY(D3DXMATRIX *pout, FLOAT angle);
+D3DXMATRIX* WINAPI D3DXMatrixMultiply(D3DXMATRIX *pout, const D3DXMATRIX *pm1, const D3DXMATRIX *pm2);
+D3DXMATRIX* WINAPI D3DXMatrixLookAtRH(D3DXMATRIX *pout, const D3DXVECTOR3 *peye, const D3DXVECTOR3 *pat, const D3DXVECTOR3 *pup);
+D3DXMATRIX* WINAPI D3DXMatrixPerspectiveFovRH(D3DXMATRIX *pout, FLOAT fovy, FLOAT aspect, FLOAT zn, FLOAT zf);
+
+
+static LPDIRECT3D             d3d          = NULL;
+static LPDIRECT3DDEVICE       device       = NULL;
+static LPDIRECT3DVERTEXBUFFER vertexBuffer = NULL;
+static LPDIRECT3DINDEXBUFFER  indexBuffer  = NULL;
+static LPDIRECT3DTEXTURE      texture1     = NULL;
+static D3DPRESENT_PARAMETERS  presentParms;
+static LONG windowWidth=300, windowHeight=300;
+static HINSTANCE hInstance;
+
+/* all allowed formats */
+static const struct
+{
+    D3DFORMAT format;
+    const char* name;
+} displayFormats[]=
+{
+    {D3DFMT_A1R5G5B5,"16-bit (1:5:5:5)"},
+#if D3D_VER==9
+    {D3DFMT_A2R10G10B10,"32-bit (2:10:10:10)"},
+#endif
+    {D3DFMT_A8R8G8B8,"32-bit (8:8:8:8)"},
+    {D3DFMT_R5G6B5,"16-bit (5:6:5)"},
+    {D3DFMT_X1R5G5B5,"15-bit (5:5:5)"},
+    {D3DFMT_X8R8G8B8,"24-bit (8:8:8)"},
+};
+static const UINT displayFormatCount=sizeof displayFormats/sizeof displayFormats[0];
+
+static D3DDISPLAYMODE getDisplayMode(UINT index)
+{
+    const int adapter=D3DADAPTER_DEFAULT;
+    D3DDISPLAYMODE dm={0};
+    UINT fmt;
+    UINT currentIndex=0;
+#if D3D_VER==9
+    for(fmt=0;fmt<displayFormatCount;++fmt)
+    {
+        const D3DFORMAT format=displayFormats[fmt].format;
+#else
+    (void)fmt;
+    {
+#endif
+        const UINT modeCount=ID3D_GetAdapterModeCount(d3d,adapter,format);
+        UINT mode=0;
+        for(;mode<modeCount;++mode)
+        {
+            if(FAILED(ID3D_EnumAdapterModes(d3d,adapter,format,mode,&dm)))
+                continue;
+            if(currentIndex!=index)
+            {
+                ++currentIndex;
+                continue;
+            }
+            return dm;
+        }
+    }
+    dm.Format=D3DFMT_UNKNOWN;
+    return dm;
+}
+
+static D3DFORMAT findRequestedVideoModeFormat(void)
+{
+    D3DDISPLAYMODE dm;
+    int mode;
+    for(mode=0;;++mode)
+    {
+        dm=getDisplayMode(mode);
+        if(dm.Format==D3DFMT_UNKNOWN)
+            break;
+        switch(fullscreenBits)
+        {
+        case 16:
+            if(dm.Format==D3DFMT_A1R5G5B5 ||
+               dm.Format==D3DFMT_R5G6B5 ||
+               dm.Format==D3DFMT_X1R5G5B5)
+                return dm.Format;
+            break;
+        case 24:
+            if(dm.Format==D3DFMT_X8R8G8B8)
+                return dm.Format;
+            break;
+        case 32:
+            if(dm.Format==D3DFMT_A8R8G8B8
+#if D3D_VER==9
+               || dm.Format==D3DFMT_A2R10G10B10
+#endif
+              )
+                return dm.Format;
+            break;
+        default:
+            return D3DFMT_UNKNOWN;
+        }
+    }
+    return D3DFMT_UNKNOWN;
+}
+
+static void fillPresentationParms(HWND hwnd)
+{
+    D3DDISPLAYMODE dm;
+    if(FAILED(ID3D_FUNC(GetAdapterDisplayMode)(d3d,D3DADAPTER_DEFAULT,&dm)))
+        fatalError(hInstance,DEMO_STATUS_ERR_GET_ADAPTER_MODE);
+
+    ZeroMemory(&presentParms, sizeof presentParms);
+    presentParms.Windowed               = !fullscreen;
+    presentParms.SwapEffect             = D3DSWAPEFFECT_DISCARD;
+    presentParms.BackBufferFormat       = dm.Format;
+    presentParms.BackBufferCount        = 1;
+    if(fullscreen)
+    {
+        presentParms.BackBufferWidth    = fullscreenWidth ? fullscreenWidth : dm.Width;
+        presentParms.BackBufferHeight   = fullscreenHeight ? fullscreenHeight : dm.Height;
+        /* in fullscreen mode we don't get WM_SIZE, but these
+           sizes are used to setup projection matrix */
+        windowWidth=presentParms.BackBufferWidth;
+        windowHeight=presentParms.BackBufferHeight;
+
+        presentParms.FullScreen_RefreshRateInHz = fullscreenFreq;
+        if(fullscreenBits)
+        {
+            presentParms.BackBufferFormat=findRequestedVideoModeFormat();
+            if(presentParms.BackBufferFormat==D3DFMT_UNKNOWN)
+                fatalError(hInstance,DEMO_STATUS_ERR_RESOLUTION_CHANGE);
+        }
+    }
+    else
+    {
+        presentParms.BackBufferWidth    = windowWidth;
+        presentParms.BackBufferHeight   = windowHeight;
+    }
+    presentParms.EnableAutoDepthStencil = TRUE;
+    presentParms.AutoDepthStencilFormat = D3DFMT_D16;
+    presentParms.hDeviceWindow          = hwnd;
+#if D3D_VER==8
+    if(setVsyncMode && !fullscreen)
+    {
+        WCHAR message[STRING_MAX];
+        WCHAR caption[STRING_MAX];
+        message[0]=0;
+        caption[0]=0;
+        LoadStringW(hInstance,STRING_WARN_VSYNC_D3D8,message,sizeof message/sizeof message[0]);
+        LoadStringW(hInstance,STRING_WARNING,caption,sizeof caption/sizeof caption[0]);
+        if(MessageBoxW(NULL,message,caption,MB_YESNO|MB_ICONEXCLAMATION)==IDNO)
+            setVsyncMode=FALSE;
+    }
+#endif
+    if(setVsyncMode)
+    {
+        presentParms.PresentationInterval = vsync ? D3DPRESENT_INTERVAL_ONE
+                                                  : D3DPRESENT_INTERVAL_IMMEDIATE;
+    }
+}
+
+static void initD3D(HWND hwnd)
+{
+    HRESULT result;
+    if(!(d3d = Direct3DCreate(D3D_SDK_VERSION)))
+        fatalError(hInstance,DEMO_STATUS_ERR_D3D_INTERFACE);
+
+    fillPresentationParms(hwnd);
+    if(FAILED(result=ID3D_FUNC(CreateDevice)(d3d,D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
+                                             D3DCREATE_SOFTWARE_VERTEXPROCESSING,
+                                             &presentParms, &device)))
+    {
+        switch(result)
+        {
+        case D3DERR_INVALIDCALL:
+            fatalError(hInstance,DEMO_STATUS_ERR_D3D_DEVICE_INVALID_CALL);
+        case D3DERR_NOTAVAILABLE:
+            fatalError(hInstance,DEMO_STATUS_ERR_D3D_DEVICE_NOT_AVAILABLE);
+        case D3DERR_OUTOFVIDEOMEMORY:
+            fatalError(hInstance,DEMO_STATUS_ERR_D3D_DEVICE_OUT_OF_VIDEO_RAM);
+        default:
+            fatalError(hInstance,DEMO_STATUS_ERR_D3D_DEVICE_UNKNOWN_ERROR);
+        }
+    }
+}
+
+static void initLightAndMaterial(void)
+{
+    {
+        D3DMATERIAL material;
+        ZeroMemory(&material, sizeof(D3DMATERIAL));
+        material.Diffuse.r = material.Ambient.r = 1.;
+        material.Diffuse.g = material.Ambient.g = 1.;
+        material.Diffuse.b = material.Ambient.b = 1.;
+        material.Diffuse.a = material.Ambient.a = 1.;
+        ID3D_DEV_FUNC(SetMaterial)(device,&material);
+    }
+    {
+        D3DLIGHT light;
+        ZeroMemory(&light, sizeof(D3DLIGHT));
+        light.Type       = D3DLIGHT_DIRECTIONAL;
+        light.Diffuse.r  = 1;
+        light.Diffuse.g  = 1;
+        light.Diffuse.b  = 1;
+        light.Diffuse.a  = 1;
+
+        light.Direction.z=1;
+
+        ID3D_DEV_FUNC(SetLight)(device,0, &light);
+        ID3D_DEV_FUNC(LightEnable)(device,0, TRUE);
+
+        ID3D_DEV_FUNC(SetRenderState)(device,D3DRS_LIGHTING, TRUE);
+        ID3D_DEV_FUNC(SetRenderState)(device,D3DRS_AMBIENT, 0xff000000);
+    }
+}
+
+static void createTexture(LPDIRECT3DDEVICE device, LPDIRECT3DTEXTURE* tex)
+{
+    HRESULT res;
+    D3DLOCKED_RECT rect;
+    UINT width, height;
+    void* data;
+    const int status=readTexture(hInstance,&data,&width,&height);
+    if(status!=DEMO_STATUS_SUCCESS)
+        fatalError(hInstance,status);
+
+    if(FAILED(res=ID3DDEV_CreateTexture(device,width,height,1,0,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,tex)))
+        fatalError(hInstance,DEMO_STATUS_ERR_TEXTURE_ALLOCATION);
+    if(FAILED(res=ID3D_TEX_FUNC(LockRect)(*tex,0,&rect,NULL,D3DLOCK_DISCARD)))
+        fatalError(hInstance,DEMO_STATUS_ERR_TEXTURE_UPLOADING);
+    memcpy(rect.pBits,data,width*height*4);
+    if(FAILED(res=ID3D_TEX_FUNC(UnlockRect)(*tex,0)))
+        fatalError(hInstance,DEMO_STATUS_ERR_TEXTURE_UNLOCK);
+    free(data);
+}
+
+
+struct CubeVertex
+{
+    FLOAT x,  y,  z;
+    FLOAT nx, ny, nz;
+    FLOAT u, v;
+};
+static const int CubeVertexFormat=D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1;
+
+static HRESULT initScene(void)
+{
+    static const struct CubeVertex vertices[] =
+    {
+    //   x  y  z  nx ny nz   u v
+       { 1,-1,-1,  0, 0,-1,  0,1},
+       { 1, 1,-1,  0, 0,-1,  0,0},
+       {-1, 1,-1,  0, 0,-1,  1,0},
+       {-1,-1,-1,  0, 0,-1,  1,1},
+
+       {-1,-1,-1, -1, 0, 0,  0,1},
+       {-1, 1,-1, -1, 0, 0,  0,0},
+       {-1, 1, 1, -1, 0, 0,  1,0},
+       {-1,-1, 1, -1, 0, 0,  1,1},
+
+       {-1,-1, 1,  0, 0, 1,  0,1},
+       {-1, 1, 1,  0, 0, 1,  0,0},
+       { 1, 1, 1,  0, 0, 1,  1,0},
+       { 1,-1, 1,  0, 0, 1,  1,1},
+
+       { 1,-1, 1,  1, 0, 0,  0,1},
+       { 1, 1, 1,  1, 0, 0,  0,0},
+       { 1, 1,-1,  1, 0, 0,  1,0},
+       { 1,-1,-1,  1, 0, 0,  1,1},
+
+       { 1,-1,-1,  0,-1, 0,  0,1},
+       {-1,-1,-1,  0,-1, 0,  0,0},
+       {-1,-1, 1,  0,-1, 0,  1,0},
+       { 1,-1, 1,  0,-1, 0,  1,1},
+
+       { 1, 1, 1,  0, 1, 0,  0,1},
+       {-1, 1, 1,  0, 1, 0,  0,0},
+       {-1, 1,-1,  0, 1, 0,  1,0},
+       { 1, 1,-1,  0, 1, 0,  1,1},
+    };
+    static const unsigned short indices[]=
+    {
+         0, 1, 2,   2, 3, 0,
+         4, 5, 6,   6, 7, 4,
+         8, 9,10,  10,11, 8,
+        12,13,14,  14,15,12,
+        16,17,18,  18,19,16,
+        20,21,22,  22,23,20,
+    };
+    VertexBufferData * buf;
+    if(!texture1)
+        createTexture(device, &texture1);
+
+    if(!vertexBuffer)
+        if(FAILED(ID3DDEV_CreateVertexBuffer(device,sizeof vertices,0,CubeVertexFormat,D3DPOOL_MANAGED,&vertexBuffer)))
+            fatalError(hInstance,DEMO_STATUS_ERR_VERTEX_BUFFER_CREATE);
+    if(FAILED(ID3D_VERT_BUF_FUNC(Lock)(vertexBuffer,0,sizeof vertices,&buf,0)))
+        fatalError(hInstance,DEMO_STATUS_ERR_VERTEX_BUFFER_LOCK);
+    memcpy(buf, vertices, sizeof vertices);
+    ID3D_VERT_BUF_FUNC(Unlock)(vertexBuffer);
+
+    if(!indexBuffer)
+        if(FAILED(ID3DDEV_CreateIndexBuffer(device,sizeof indices,0,D3DFMT_INDEX16,D3DPOOL_MANAGED,&indexBuffer)))
+            fatalError(hInstance,DEMO_STATUS_ERR_INDEX_BUFFER_CREATE);
+    if(FAILED(ID3D_IND_BUF_FUNC(Lock)(indexBuffer,0,sizeof indices,&buf,0)))
+        fatalError(hInstance,DEMO_STATUS_ERR_INDEX_BUFFER_LOCK);
+    memcpy(buf,indices,sizeof indices);
+    ID3D_IND_BUF_FUNC(Unlock)(indexBuffer);
+
+    initLightAndMaterial();
+
+    ID3D_DEV_FUNC(SetRenderState)(device,D3DRS_CULLMODE, D3DCULL_CCW);
+    ID3D_DEV_FUNC(SetRenderState)(device,D3DRS_ZENABLE, D3DZB_TRUE);
+
+    return S_OK;
+}
+
+static void setupMatrices(void)
+{
+    {
+        const FLOAT angle = GetTickCount()%3500 * 2*D3DX_PI / 3500.;
+        D3DXMATRIX model, rotX, rotY;
+        D3DXMatrixRotationX(&rotX, angle);
+        D3DXMatrixRotationY(&rotY, angle);
+        D3DXMatrixMultiply(&model,&rotY,&rotX);
+        ID3D_DEV_FUNC(SetTransform)(device,D3DTS_WORLD,&model);
+    }
+    {
+        D3DXMATRIX view;
+        const D3DXVECTOR3 eye={0, 0,-5},
+                          at={0, 0, 0},
+                          up={0, 1, 0};
+        D3DXMatrixLookAtRH(&view,&eye,&at,&up);
+        ID3D_DEV_FUNC(SetTransform)(device,D3DTS_VIEW, &view);
+    }
+    {
+        D3DXMATRIX proj;
+        const FLOAT aspect=(FLOAT)windowWidth/windowHeight;
+        D3DXMatrixPerspectiveFovRH(&proj,D3DX_PI/4,aspect,1,100);
+        if(aspect<1)
+        {
+            // Make the cube fit in the window
+            proj._11*=aspect;
+            proj._22*=aspect;
+        }
+        ID3D_DEV_FUNC(SetTransform)(device,D3DTS_PROJECTION,&proj);
+    }
+}
+
+static void render(void)
+{
+    const D3DCOLOR backgroundColor=D3DCOLOR_XRGB(bgRed,bgGreen,bgBlue);
+    ID3D_DEV_FUNC(Clear)(device,0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,backgroundColor,1,0);
+    ID3D_DEV_FUNC(BeginScene)(device);
+
+    setupMatrices();
+
+    ID3DDEV_SetStreamSource(device,0, vertexBuffer,sizeof(struct CubeVertex));
+    ID3D_DEV_FUNC(SetFVF)(device,CubeVertexFormat);
+    ID3DDEV_SetIndices(device,indexBuffer);
+    ID3D_DEV_FUNC(SetTexture)(device, 0, (LPDIRECT3DBASETEXTURE)texture1);
+    ID3D_DEV_FUNC(SetSamplerState)(device,0, D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
+    ID3D_DEV_FUNC(SetSamplerState)(device,0, D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
+    ID3D_DEV_FUNC(SetTextureStageState)(device,0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+    ID3D_DEV_FUNC(SetTextureStageState)(device,0, D3DTSS_COLOROP, D3DTOP_MODULATE);
+    ID3DDEV_DrawIndexedPrimitive(device,D3DPT_TRIANGLELIST, 0, 36, 0, 12);
+
+    ID3D_DEV_FUNC(EndScene)(device);
+    ID3D_DEV_FUNC(Present)(device, NULL, NULL, NULL, NULL);
+}
+
+static void deleteDirect3D(void)
+{
+    if(indexBuffer) ID3D_IND_BUF_FUNC(Release)(indexBuffer);
+    if(vertexBuffer) ID3D_VERT_BUF_FUNC(Release)(vertexBuffer);
+    if(texture1) ID3D_TEX_FUNC(Release)(texture1);
+    if(device) ID3D_DEV_FUNC(Release)(device);
+    if(d3d) ID3D_FUNC(Release)(d3d);
+}
+
+static void drawIteration(void)
+{
+    if(device && vertexBuffer && indexBuffer)
+    {
+        static const double period=5;
+        static int frameCount=0;
+        static DWORD oldTime;
+        DWORD newTime;
+        double elapsed;
+
+        if(!oldTime)
+            oldTime=GetTickCount();
+        render();
+        ++frameCount;
+        newTime=GetTickCount();
+        elapsed=(newTime-oldTime)/1000.;
+        if(elapsed>period)
+        {
+            printf("%d frames in %.1f seconds = %.3f FPS\n",frameCount,elapsed,frameCount/elapsed);
+            fflush(stdout);
+            oldTime=newTime;
+            frameCount=0;
+        }
+    }
+}
+
+static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    switch(msg)
+    {
+    case WM_DESTROY:
+        deleteDirect3D();
+        PostQuitMessage(0);
+        return 0;
+    case WM_KEYDOWN:
+        if(wparam==VK_ESCAPE)
+            PostQuitMessage(0);
+        return 0;
+    case WM_SIZE:
+    {
+        windowWidth=LOWORD(lparam);
+        windowHeight=HIWORD(lparam);
+        if(windowWidth==0 || windowHeight==0)
+            break;
+
+        presentParms.BackBufferWidth=windowWidth;
+        presentParms.BackBufferHeight=windowHeight;
+
+        if(FAILED(ID3D_DEV_FUNC(Reset)(device,&presentParms)))
+            fatalError(hInstance,DEMO_STATUS_ERR_RESET_DEVICE);
+        initScene();
+        return 0;
+    }
+    case WM_PAINT:
+    {
+        PAINTSTRUCT ps;
+        BeginPaint(hwnd, &ps);
+        drawIteration();
+        EndPaint(hwnd, &ps);
+        return 0;
+    }
+    }
+    return DefWindowProcW(hwnd, msg, wparam, lparam);
+}
+
+int APPEND_VERSION(run_d3d)(HINSTANCE hInst, int cmdShow)
+{
+    static const WCHAR caption[]={'W','i','n','e','D','3','D','0'+D3D_VER,' ','D','e','m','o',0};
+    static const WCHAR className[]={'W','i','n','e','-','D','e','m','o',0};
+    MSG msg={0};
+    HWND hwnd;
+    WNDCLASSEXW windowClass;
+    hInstance=hInst;
+    windowClass.cbSize        = sizeof windowClass;
+    windowClass.style         = 0;
+    windowClass.lpfnWndProc   = wndProc;
+    windowClass.cbClsExtra    = 0;
+    windowClass.cbWndExtra    = 0;
+    windowClass.hInstance     = hInst;
+    windowClass.hIcon         = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
+    windowClass.hCursor       = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
+    windowClass.hbrBackground = CreateSolidBrush(RGB(bgRed,bgGreen,bgBlue));
+    windowClass.lpszMenuName  = NULL;
+    windowClass.lpszClassName = className;
+    windowClass.hIconSm       = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
+    if(!RegisterClassExW(&windowClass)) return 1;
+
+    if(!(hwnd = CreateWindowExW(0,windowClass.lpszClassName,
+                                caption,WS_OVERLAPPEDWINDOW,
+                                CW_USEDEFAULT,CW_USEDEFAULT,windowWidth,windowHeight,
+                                NULL,NULL,hInst,NULL))) return 2;
+    initD3D(hwnd);
+
+    ShowWindow(hwnd,cmdShow);
+    /* In fullscreen mode we don't get WM_SIZE, so initialize the scene here */
+    if(fullscreen)
+        initScene();
+    UpdateWindow(hwnd);
+
+    while(1)
+    {
+        if(PeekMessageW(&msg,NULL,0,0,PM_REMOVE))
+        {
+            if(msg.message==WM_QUIT || (msg.message==WM_TIMER && msg.wParam==exitTimerId))
+                break;
+            TranslateMessage(&msg);
+            DispatchMessageW(&msg);
+        }
+        else
+        {
+            // Directly draw here. InvalidateRect can slow things down up to 50%.
+            drawIteration();
+        }
+    }
+
+    return msg.wParam;
+}
+
+int APPEND_VERSION(listModes_d3d)(HINSTANCE hInst)
+{
+    int mode;
+    if(!(d3d = Direct3DCreate(D3D_SDK_VERSION)))
+        fatalError(hInstance,DEMO_STATUS_ERR_D3D_INTERFACE);
+
+    for(mode=0;;++mode)
+    {
+        const D3DDISPLAYMODE dm=getDisplayMode(mode);
+        UINT fmtLookup;
+        if(dm.Format==D3DFMT_UNKNOWN)
+            break;
+        for(fmtLookup=0;fmtLookup<displayFormatCount;++fmtLookup)
+        {
+            if(displayFormats[fmtLookup].format==dm.Format)
+            {
+                printf("%ux%u@%u, %s\n",dm.Width,dm.Height,dm.RefreshRate,displayFormats[fmtLookup].name);
+                break;
+            }
+            /* Print unexpected format in hex */
+            if(fmtLookup==displayFormatCount)
+                printf("%ux%u@%u, fmt: %#x\n",dm.Width,dm.Height,dm.RefreshRate,dm.Format);
+        }
+    }
+    return 0;
+}
diff --git a/programs/3d-demo/d3d8.c b/programs/3d-demo/d3d8.c
new file mode 100644
index 0000000..b6f3ed5
--- /dev/null
+++ b/programs/3d-demo/d3d8.c
@@ -0,0 +1,2 @@
+#define D3D_VER 8
+#include "d3d.c"
diff --git a/programs/3d-demo/d3d9.c b/programs/3d-demo/d3d9.c
new file mode 100644
index 0000000..96f9a4a
--- /dev/null
+++ b/programs/3d-demo/d3d9.c
@@ -0,0 +1,2 @@
+#define D3D_VER 9
+#include "d3d.c"
diff --git a/programs/3d-demo/demo.rc b/programs/3d-demo/demo.rc
new file mode 100644
index 0000000..41c8912
--- /dev/null
+++ b/programs/3d-demo/demo.rc
@@ -0,0 +1,61 @@
+/*
+ * Resources 3D APIs demo
+ *
+ * Copyright 2016 Ruslan Kabatsayev
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <windows.h>
+#include "resource.h"
+
+#pragma makedep po
+
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+STRINGTABLE
+{
+    STRING_FATAL_ERROR, "Fatal Error"
+    STRING_WARNING, "Warning"
+    STRING_WARN_NO_VSYNC_EXT, "Can't set vsync mode: the necessary extension is not supported"
+    STRING_WARN_NO_VSYNC_ENTRYPOINT, "Can't set vsync mode: function entry point not found"
+    STRING_WARN_VSYNC_D3D8, "Direct3D 8 doesn't allow to request vsync mode in windowed mode.\nAttempt to do this anyway (may work in Wine)?"
+    STRING_USAGE, "Usage: 3d-demo /api:{d3d8|d3d9|wgl} [options...]\nSupported options:\n /vsync:{on|off}\n /fullscreen[:WIDTHxHEIGHT[@HZ][:BITS]]\n /listmodes\n /timeout:SEC"
+    STRING_USAGE_CAPTION, "Usage"
+    DEMO_STATUS_SUCCESS, "Success"
+    DEMO_STATUS_ERR_TEXTURE_FILE_READ, "Failed to read texture file"
+    DEMO_STATUS_ERR_TEXTURE_IMAGE_SIZE_GETTING, "Failed to get texture dimensions"
+    DEMO_STATUS_ERR_TEXTURE_DATA_READING, "Failed to read texture data"
+    DEMO_STATUS_ERR_TEXTURE_ALLOCATION, "Failed to allocate texture"
+    DEMO_STATUS_ERR_TEXTURE_BINDING, "Failed to bind texture"
+    DEMO_STATUS_ERR_TEXTURE_UPLOADING, "Failed to upload texture"
+    DEMO_STATUS_ERR_PIXEL_FORMAT_SETUP, "Failed to setup pixel format"
+    DEMO_STATUS_ERR_GET_ADAPTER_MODE, "Failed to get adapter video mode"
+    DEMO_STATUS_ERR_D3D_INTERFACE, "Failed to create Direct3D interface"
+    DEMO_STATUS_ERR_D3D_DEVICE_INVALID_CALL, "Failed to create Direct3D device: invalid call"
+    DEMO_STATUS_ERR_D3D_DEVICE_NOT_AVAILABLE, "Failed to create Direct3D device: not available"
+    DEMO_STATUS_ERR_D3D_DEVICE_OUT_OF_VIDEO_RAM, "Failed to create Direct3D device: out of video memory"
+    DEMO_STATUS_ERR_D3D_DEVICE_UNKNOWN_ERROR, "Failed to create Direct3D device: unknown error"
+    DEMO_STATUS_ERR_TEXTURE_UNLOCK, "Failed to unlock texture bits"
+    DEMO_STATUS_ERR_VERTEX_BUFFER_CREATE, "Failed to create vertex buffer"
+    DEMO_STATUS_ERR_VERTEX_BUFFER_LOCK, "Failed to lock vertex buffer"
+    DEMO_STATUS_ERR_INDEX_BUFFER_CREATE, "Failed to create index buffer"
+    DEMO_STATUS_ERR_INDEX_BUFFER_LOCK, "Failed to lock index buffer"
+    DEMO_STATUS_ERR_RESET_DEVICE, "Failed to reset the device"
+    DEMO_STATUS_ERR_SETUP_TEXTURE, "Failed to setup texture"
+    DEMO_STATUS_ERR_RESOLUTION_CHANGE, "Failed to set resolution"
+}
+
+IDR_TEXTURE RCDATA "winehq_logo_glass.png"
diff --git a/programs/3d-demo/main.c b/programs/3d-demo/main.c
new file mode 100644
index 0000000..6b72571
--- /dev/null
+++ b/programs/3d-demo/main.c
@@ -0,0 +1,175 @@
+/*
+ * 3D APIs demo
+ *
+ * Copyright 2016 Ruslan Kabatsayev
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "common.h"
+#include <shellapi.h>
+#include "resource.h"
+int run_d3d8(HINSTANCE hInst, int cmdShow);
+int run_d3d9(HINSTANCE hInst, int cmdShow);
+int run_wgl(HINSTANCE hInst, int cmdShow);
+int listModes_d3d8(HINSTANCE hInst);
+int listModes_d3d9(HINSTANCE hInst);
+int listModes_wgl(HINSTANCE hInst);
+
+enum API
+{
+    API_NONE,
+    API_WGL,
+    API_D3D8,
+    API_D3D9,
+} apiToUse=API_NONE;
+BOOL listModes=FALSE;
+
+HINSTANCE hInstance;
+BOOL setVsyncMode=FALSE;
+BOOL vsync;
+BOOL fullscreen=FALSE;
+DWORD fullscreenWidth=0, fullscreenHeight=0, fullscreenFreq=0, fullscreenBits=0;
+UINT_PTR exitTimerId;
+
+#include <stdio.h>
+BOOL processCommandLine(int argc, WCHAR** argv)
+{
+    static const WCHAR api_wgl[]={'/','a','p','i',':','w','g','l',0};
+    static const WCHAR api_d3d8[]={'/','a','p','i',':','d','3','d','8',0};
+    static const WCHAR api_d3d9[]={'/','a','p','i',':','d','3','d','9',0};
+    static const WCHAR vsync_on[]={'/','v','s','y','n','c',':','o','n',0};
+    static const WCHAR vsync_off[]={'/','v','s','y','n','c',':','o','f','f',0};
+    static const WCHAR fullscreen_on[]={'/','f','u','l','l','s','c','r','e','e','n',0};
+    static const WCHAR listmodes[]={'/','l','i','s','t','m','o','d','e','s',0};
+    static const WCHAR fullscreen_modePrefix[]={'/','f','u','l','l','s','c','r','e','e','n',':',0};
+    static const WCHAR timeout_secPrefix[]={'/','t','i','m','e','o','u','t',':',0};
+    int i=0;
+    for(;i<argc;++i)
+    {
+        LPWSTR option=argv[i];
+        if(!wcscmp(option,api_wgl))
+            apiToUse=API_WGL;
+        else if(!wcscmp(option,api_d3d8))
+            apiToUse=API_D3D8;
+        else if(!wcscmp(option,api_d3d9))
+            apiToUse=API_D3D9;
+        else if(wcsstr(option,timeout_secPrefix)==option)
+        {
+            const int prefixLen=sizeof timeout_secPrefix/sizeof timeout_secPrefix[0]-1;
+            const WCHAR*const secBegin=option+prefixLen;
+            static const WCHAR format[]={'%','u','%','c',0};
+            unsigned sec;
+            char guard;
+            if(swscanf(secBegin,format,&sec,&guard)!=1)
+                return FALSE;
+            exitTimerId=SetTimer(NULL,0,sec*1000,NULL);
+        }
+        else if(!wcscmp(option,vsync_on))
+        {
+            setVsyncMode=TRUE;
+            vsync=TRUE;
+        }
+        else if(!wcscmp(option,vsync_off))
+        {
+            setVsyncMode=TRUE;
+            vsync=FALSE;
+        }
+        else if(!wcscmp(option,fullscreen_on))
+            fullscreen=TRUE;
+        else if(wcsstr(option,fullscreen_modePrefix)==option)
+        {
+            const int prefixLen=sizeof fullscreen_modePrefix/sizeof fullscreen_modePrefix[0]-1;
+            const WCHAR*const modeBegin=option+prefixLen;
+            DWORD a,b;
+            WCHAR op1,op2,guard; /* guard is to check for trailing chars */
+            static const WCHAR format[]={'%','u','x','%','u','%','c','%','u','%','c','%','u','%','c',0};
+            const int fieldCount=swscanf(modeBegin,format,&fullscreenWidth,
+                                                          &fullscreenHeight,
+                                                          &op1,&a,&op2,&b,&guard);
+            if(fieldCount==3||fieldCount==5||fieldCount>6)
+                return FALSE;
+            if(fieldCount>3)
+            {
+               if(op1=='@')
+                   fullscreenFreq=a;
+               else if(op1==':')
+                   fullscreenBits=a;
+               else
+                   return FALSE;
+            }
+            if(fieldCount>5)
+            {
+                if(op2==op1)
+                    return FALSE;
+                if(op2=='@')
+                    fullscreenFreq=b;
+                else if(op2==':')
+                    fullscreenBits=b;
+               else
+                   return FALSE;
+            }
+            fullscreen=TRUE;
+        }
+        else if(!wcscmp(option,listmodes))
+            listModes=TRUE;
+        else
+            return FALSE;
+    }
+    return TRUE;
+}
+
+int usage(void)
+{
+    WCHAR message[STRING_MAX];
+    WCHAR caption[STRING_MAX];
+    message[0]=0;
+    caption[0]=0;
+    LoadStringW(hInstance,STRING_USAGE,message,sizeof message/sizeof message[0]);
+    LoadStringW(hInstance,STRING_USAGE_CAPTION,caption,sizeof caption/sizeof caption[0]);
+    MessageBoxW(NULL,message,caption,MB_OK|MB_ICONEXCLAMATION);
+    return -1;
+}
+
+int run(int argc, WCHAR** argv, int cmdShow)
+{
+    if(!processCommandLine(argc,argv))
+        return usage();
+    switch(apiToUse)
+    {
+    case API_WGL:
+        if(listModes)
+            return listModes_wgl(hInstance);
+        return run_wgl(hInstance,cmdShow);
+    case API_D3D8:
+        if(listModes)
+            return listModes_d3d8(hInstance);
+        return run_d3d8(hInstance,cmdShow);
+    case API_D3D9:
+        if(listModes)
+            return listModes_d3d9(hInstance);
+        return run_d3d9(hInstance,cmdShow);
+    default:
+        return usage();
+    }
+}
+
+int WINAPI wWinMain(HINSTANCE hInst,HINSTANCE hPrev,LPWSTR cmdLine,int cmdShow)
+{
+    int argc;
+    LPWSTR*const argv=CommandLineToArgvW(cmdLine,&argc);
+    hInstance=hInst;
+    return run(argc,argv,cmdShow);
+}
diff --git a/programs/3d-demo/resource.h b/programs/3d-demo/resource.h
new file mode 100644
index 0000000..3523db2
--- /dev/null
+++ b/programs/3d-demo/resource.h
@@ -0,0 +1,33 @@
+#define STRING_MAX   1024
+
+#define IDR_TEXTURE                                     10000
+#define STRING_WARN_VSYNC_D3D8                          1001
+#define STRING_USAGE                                    1002
+#define STRING_USAGE_CAPTION                            1003
+#define STRING_UNKNOWN_OPTION                           1004
+#define STRING_WARN_NO_VSYNC_ENTRYPOINT                 1005
+#define STRING_WARN_NO_VSYNC_EXT                        1006
+#define STRING_FATAL_ERROR                              1007
+#define STRING_WARNING                                  1008
+#define DEMO_STATUS_SUCCESS                             100
+#define DEMO_STATUS_ERR_TEXTURE_FILE_READ               101
+#define DEMO_STATUS_ERR_TEXTURE_IMAGE_SIZE_GETTING      102
+#define DEMO_STATUS_ERR_TEXTURE_DATA_READING            103
+#define DEMO_STATUS_ERR_TEXTURE_ALLOCATION              104
+#define DEMO_STATUS_ERR_TEXTURE_BINDING                 105
+#define DEMO_STATUS_ERR_TEXTURE_UPLOADING               106
+#define DEMO_STATUS_ERR_PIXEL_FORMAT_SETUP              107
+#define DEMO_STATUS_ERR_GET_ADAPTER_MODE                108
+#define DEMO_STATUS_ERR_D3D_INTERFACE                   109
+#define DEMO_STATUS_ERR_D3D_DEVICE_INVALID_CALL         110
+#define DEMO_STATUS_ERR_D3D_DEVICE_NOT_AVAILABLE        111
+#define DEMO_STATUS_ERR_D3D_DEVICE_OUT_OF_VIDEO_RAM     112
+#define DEMO_STATUS_ERR_D3D_DEVICE_UNKNOWN_ERROR        113
+#define DEMO_STATUS_ERR_TEXTURE_UNLOCK                  114
+#define DEMO_STATUS_ERR_VERTEX_BUFFER_CREATE            115
+#define DEMO_STATUS_ERR_VERTEX_BUFFER_LOCK              116
+#define DEMO_STATUS_ERR_INDEX_BUFFER_CREATE             117
+#define DEMO_STATUS_ERR_INDEX_BUFFER_LOCK               118
+#define DEMO_STATUS_ERR_RESET_DEVICE                    119
+#define DEMO_STATUS_ERR_SETUP_TEXTURE                   120
+#define DEMO_STATUS_ERR_RESOLUTION_CHANGE               121
diff --git a/programs/3d-demo/wgl.c b/programs/3d-demo/wgl.c
new file mode 100644
index 0000000..b472e65
--- /dev/null
+++ b/programs/3d-demo/wgl.c
@@ -0,0 +1,473 @@
+/*
+ * 3D APIs demo
+ *
+ * Copyright 2016 Ruslan Kabatsayev
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "common.h"
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <wine/wgl.h>
+#include <wine/wglext.h> /* for GL_BGRA */
+
+#include "resource.h"
+
+static LONG windowWidth=300, windowHeight=300;
+static GLuint displayList=0;
+static GLuint texture1=0;
+static HINSTANCE hInstance;
+static HDC hdc;
+
+static void clearOpenGLError(void)
+{
+    while(glGetError()!=GL_NO_ERROR);
+}
+
+BOOL extensionIsSupported(const char*const exts, const char*const extension)
+{
+    size_t extsLen;
+    size_t refLen;
+    size_t begin=0;
+    if(!exts) return FALSE;
+    extsLen=strlen(exts);
+    refLen=strlen(extension);
+
+    while(begin<extsLen)
+    {
+        const char* extFound=strstr(exts+begin,extension);
+        if(!extFound) return FALSE;
+        /* If not first in the list and is not a continuation of a
+           space-separated string, it's not a match. Same for the case
+           when it's not the last and doesn't have a space after it */
+        if((extFound!=exts && extFound[-1]!=' ') ||
+           (extFound[refLen]!='\0' && extFound[refLen]!=' '))
+        {
+            begin=extFound-exts+1;
+            continue;
+        }
+        return TRUE;
+    }
+    return FALSE;
+}
+
+BOOL openglExtensionIsSupported(const char*const extension)
+{
+    return extensionIsSupported((const char*)glGetString(GL_EXTENSIONS),extension);
+}
+
+BOOL wglExtensionIsSupported(const char*const extension)
+{
+    typedef const char*(*PWGLGETEXTENSIONSSTRINGEXTPROC)(void);
+    const PWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsStringEXT
+        =(PWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT");
+    if(!wglGetExtensionsStringEXT)
+        return FALSE;
+    return extensionIsSupported(wglGetExtensionsStringEXT(),extension);
+}
+
+static GLuint createTexture(void)
+{
+    GLuint texture;
+    UINT width, height;
+    void* data;
+    int status;
+    GLuint glErr;
+
+    clearOpenGLError();
+    glGenTextures(1,&texture);
+    if(glGetError()!=GL_NO_ERROR || !texture)
+        fatalError(hInstance,DEMO_STATUS_ERR_TEXTURE_ALLOCATION);
+    glBindTexture(GL_TEXTURE_2D,texture);
+    if(glGetError()!=GL_NO_ERROR)
+        fatalError(hInstance,DEMO_STATUS_ERR_TEXTURE_BINDING);
+    
+    status=readTexture(hInstance,&data,&width,&height);
+    if(status!=DEMO_STATUS_SUCCESS)
+        fatalError(hInstance,status);
+    glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,width,height,
+                 0,GL_BGRA,GL_UNSIGNED_BYTE,data);
+    free(data);
+    glErr=glGetError();
+    if(glErr!=GL_NO_ERROR) fatalError(hInstance,DEMO_STATUS_ERR_SETUP_TEXTURE);
+
+    return texture;
+}
+
+static void setupMatrices(void)
+{
+    {
+        const GLfloat angle = GetTickCount()%3500 * 360 / 3500.;
+
+        glMatrixMode(GL_MODELVIEW);
+        glLoadIdentity();
+        glRotatef(angle,1,0,0);
+        glRotatef(angle,0,1,0);
+    }
+    {
+        /* The matrix is mostly the result of
+            gluPerspective(180./4, aspect, 1, 100);
+            gluLookAt(0,0,-5, 0,0,0, 0,1,0);
+           but if aspect<1, multiplies two top-left diagonal
+           elements by aspect to make image fit viewport */
+        const GLfloat aspect=(GLfloat)windowWidth/windowHeight;
+        const GLfloat fovy=MATH_PI/4;
+        const GLfloat f=1/tan(fovy/2);
+        const GLfloat projection[4*4]=
+            {
+                -(aspect<1 ? f : f/aspect), 0, 0, 0,
+                 0, (aspect<1 ? f*aspect : f), 0, 0,
+                 0,          0,    101./99,       1,
+                 0,          0,    305./99,       5,
+            };
+        glMatrixMode(GL_PROJECTION);
+        glLoadMatrixf(projection);
+    }
+}
+
+static void initLightAndMaterial(void)
+{
+    {
+        const GLfloat color[4]={1,1,1,1};
+        glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
+    }
+    {
+        const GLfloat diffuseColor[4]={1,1,1,1};
+        const GLfloat position[4]={0,0,-1,0};
+        glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseColor);
+        glLightfv(GL_LIGHT0, GL_POSITION, position);
+    }
+    glEnable(GL_LIGHTING);
+    glEnable(GL_LIGHT0);
+    {
+        const GLfloat globalAmbient[4]={0,0,0,1};
+        glLightModelfv(GL_LIGHT_MODEL_AMBIENT,globalAmbient);
+    }
+}
+
+typedef struct CubeVertex
+{
+    GLfloat x,  y,  z;
+    GLfloat nx, ny, nz;
+    GLfloat u, v;
+} CubeVertex;
+
+static void initScene(void)
+{
+    static const CubeVertex vertices[] =
+    {
+    //   x  y  z  nx ny nz   u v
+       { 1,-1,-1,  0, 0,-1,  0,1},
+       { 1, 1,-1,  0, 0,-1,  0,0},
+       {-1, 1,-1,  0, 0,-1,  1,0},
+       {-1,-1,-1,  0, 0,-1,  1,1},
+
+       {-1,-1,-1, -1, 0, 0,  0,1},
+       {-1, 1,-1, -1, 0, 0,  0,0},
+       {-1, 1, 1, -1, 0, 0,  1,0},
+       {-1,-1, 1, -1, 0, 0,  1,1},
+
+       {-1,-1, 1,  0, 0, 1,  0,1},
+       {-1, 1, 1,  0, 0, 1,  0,0},
+       { 1, 1, 1,  0, 0, 1,  1,0},
+       { 1,-1, 1,  0, 0, 1,  1,1},
+
+       { 1,-1, 1,  1, 0, 0,  0,1},
+       { 1, 1, 1,  1, 0, 0,  0,0},
+       { 1, 1,-1,  1, 0, 0,  1,0},
+       { 1,-1,-1,  1, 0, 0,  1,1},
+
+       { 1,-1,-1,  0,-1, 0,  0,1},
+       {-1,-1,-1,  0,-1, 0,  0,0},
+       {-1,-1, 1,  0,-1, 0,  1,0},
+       { 1,-1, 1,  0,-1, 0,  1,1},
+
+       { 1, 1, 1,  0, 1, 0,  0,1},
+       {-1, 1, 1,  0, 1, 0,  0,0},
+       {-1, 1,-1,  0, 1, 0,  1,0},
+       { 1, 1,-1,  0, 1, 0,  1,1},
+    };
+    const GLushort indices[]=
+    {
+         0, 1, 2,   2, 3, 0,
+         4, 5, 6,   6, 7, 4,
+         8, 9,10,  10,11, 8,
+        12,13,14,  14,15,12,
+        16,17,18,  18,19,16,
+        20,21,22,  22,23,20,
+    };
+
+    if(displayList) glDeleteLists(displayList,1);
+    displayList=glGenLists(1);
+
+    glNewList(displayList,GL_COMPILE);
+        glEnableClientState(GL_VERTEX_ARRAY);
+        glEnableClientState(GL_NORMAL_ARRAY);
+        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+        glFrontFace(GL_CW);
+        glEnable(GL_CULL_FACE);
+        glEnable(GL_DEPTH_TEST);
+        glEnable(GL_TEXTURE_2D);
+
+        glVertexPointer(3, GL_FLOAT, sizeof(CubeVertex), vertices);
+        glNormalPointer(GL_FLOAT, sizeof(CubeVertex), (char*)vertices+offsetof(CubeVertex,nx));
+        glTexCoordPointer(2, GL_FLOAT, sizeof(CubeVertex), (char*)vertices+offsetof(CubeVertex,u));
+        glDrawElements(GL_TRIANGLES, sizeof indices/sizeof*indices, GL_UNSIGNED_SHORT, indices);
+
+        glDisable(GL_TEXTURE_2D);
+        glDisable(GL_DEPTH_TEST);
+        glDisable(GL_CULL_FACE);
+        glFrontFace(GL_CW);
+        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+        glDisableClientState(GL_NORMAL_ARRAY);
+        glDisableClientState(GL_VERTEX_ARRAY);
+    glEndList();
+
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    initLightAndMaterial();
+
+    texture1=createTexture();
+    glBindTexture(GL_TEXTURE_2D,texture1);
+    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+    glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
+}
+
+static void render(void)
+{
+    glClearColor(bgRed/255.,bgGreen/255.,bgBlue/255.,1);
+    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+
+    setupMatrices();
+
+    glCallList(displayList);
+
+    SwapBuffers(hdc);
+}
+
+static void setupPixelFormat(void)
+{
+    int pf;
+    PIXELFORMATDESCRIPTOR pfd = {0};
+    pfd.nSize=sizeof(PIXELFORMATDESCRIPTOR);
+    pfd.nVersion=1;
+    pfd.dwFlags=PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER | PFD_SWAP_EXCHANGE;
+    pfd.iPixelType=PFD_TYPE_RGBA;
+    pfd.cColorBits=24;
+    pfd.cDepthBits=16;
+    pfd.iLayerType=PFD_MAIN_PLANE;
+    if(!(pf=ChoosePixelFormat(hdc, &pfd)))
+        fatalError(hInstance,DEMO_STATUS_ERR_PIXEL_FORMAT_SETUP);
+    SetPixelFormat(hdc, pf, &pfd);
+}
+
+void setupVsync(void)
+{
+    BOOL (*wglSwapIntervalEXT)(int interval);
+    BOOL extSupported;
+    if(!setVsyncMode) return;
+    extSupported=wglExtensionIsSupported("WGL_EXT_swap_control");
+    if(!extSupported ||
+       !(wglSwapIntervalEXT=(BOOL (*)(int interval))wglGetProcAddress("wglSwapIntervalEXT")))
+    {
+        WCHAR message[STRING_MAX];
+        WCHAR caption[STRING_MAX];
+        message[0]=0;
+        caption[0]=0;
+        LoadStringW(hInstance, !extSupported ? STRING_WARN_NO_VSYNC_EXT
+                                             : STRING_WARN_NO_VSYNC_ENTRYPOINT
+                    ,message,sizeof message/sizeof message[0]);
+        LoadStringW(hInstance,STRING_WARNING,caption,sizeof caption/sizeof caption[0]);
+        MessageBoxW(NULL,message,caption,MB_OK|MB_ICONEXCLAMATION);
+        return;
+    }
+    wglSwapIntervalEXT(vsync?1:0);
+}
+
+void drawIteration(void)
+{
+    static const double period=5;
+    static int frameCount=0;
+    static DWORD oldTime;
+    DWORD newTime;
+    double elapsed;
+
+    if(!oldTime)
+        oldTime=GetTickCount();
+    render();
+    ++frameCount;
+    newTime=GetTickCount();
+    elapsed=(newTime-oldTime)/1000.;
+    if(elapsed>period)
+    {
+        printf("%d frames in %.1f seconds = %.3f FPS\n",frameCount,elapsed,frameCount/elapsed);
+        fflush(stdout);
+        oldTime=newTime;
+        frameCount=0;
+    }
+}
+static LRESULT APIENTRY wndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
+{
+    static HGLRC hGLRC;
+    switch (message)
+    {
+    case WM_CREATE:
+        hdc = GetDC(hwnd);
+        setupPixelFormat();
+        hGLRC = wglCreateContext(hdc);
+        wglMakeCurrent(hdc, hGLRC);
+        initScene();
+        setupVsync();
+        return 0;
+    case WM_DESTROY:
+        if(hGLRC)
+        {
+            wglMakeCurrent(NULL, NULL);
+            wglDeleteContext(hGLRC);
+        }
+        ReleaseDC(hwnd, hdc);
+        PostQuitMessage(0);
+        return 0;
+    case WM_KEYDOWN:
+        if(wparam==VK_ESCAPE)
+            PostQuitMessage(0);
+        return 0;
+    case WM_SIZE:
+        if(hGLRC)
+        {
+            windowWidth=LOWORD(lparam);
+            windowHeight=HIWORD(lparam);
+            glViewport(0, 0, windowWidth, windowHeight);
+            return 0;
+        }
+        break;
+    case WM_PAINT:
+    {
+        PAINTSTRUCT ps;
+        BeginPaint(hwnd, &ps);
+        drawIteration();
+        EndPaint(hwnd, &ps);
+        return 0;
+    }
+    }
+    return DefWindowProcW(hwnd, message, wparam, lparam);
+}
+
+int run_wgl(HINSTANCE hInst, int cmdShow)
+{
+    static const WCHAR caption[]={'W','i','n','e','W','G','L',' ','D','e','m','o',0};
+    static const WCHAR className[]={'W','i','n','e','-','D','e','m','o',0};
+    MSG msg={0};
+    HWND hwnd;
+    WNDCLASSEXW windowClass;
+    DWORD windowStyle=WS_OVERLAPPEDWINDOW;
+    hInstance=hInst;
+    windowClass.cbSize        = sizeof windowClass;
+    windowClass.style         = 0;
+    windowClass.lpfnWndProc   = wndProc;
+    windowClass.cbClsExtra    = 0;
+    windowClass.cbWndExtra    = 0;
+    windowClass.hInstance     = hInst;
+    windowClass.hIcon         = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
+    windowClass.hCursor       = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
+    windowClass.hbrBackground = CreateSolidBrush(RGB(bgRed,bgGreen,bgBlue));
+    windowClass.lpszMenuName  = NULL;
+    windowClass.lpszClassName = className;
+    windowClass.hIconSm       = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
+    if(!RegisterClassExW(&windowClass)) return 1;
+
+    if(fullscreen)
+    {
+        DEVMODEW dm;
+        dm.dmSize=sizeof dm;
+        dm.dmFields=0;
+        if(fullscreenWidth)
+        {
+            dm.dmPelsWidth=fullscreenWidth;
+            dm.dmFields|=DM_PELSWIDTH;
+            windowWidth =dm.dmPelsWidth;
+        }
+        else
+            windowWidth =GetSystemMetrics(SM_CXSCREEN);
+
+        if(fullscreenHeight)
+        {
+            dm.dmPelsHeight=fullscreenHeight;
+            dm.dmFields|=DM_PELSHEIGHT;
+            windowHeight=dm.dmPelsHeight;
+        }
+        else
+            windowHeight=GetSystemMetrics(SM_CYSCREEN);
+
+        if(fullscreenBits)
+        {
+            dm.dmBitsPerPel=fullscreenBits;
+            dm.dmFields|=DM_BITSPERPEL;
+        }
+
+        if(fullscreenFreq)
+        {
+            dm.dmDisplayFrequency=fullscreenFreq;
+            dm.dmFields|=DM_DISPLAYFREQUENCY;
+        }
+
+        if(fullscreenWidth||fullscreenHeight||fullscreenBits||fullscreenFreq)
+        {
+            if(ChangeDisplaySettingsW(&dm,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
+                fatalError(hInstance,DEMO_STATUS_ERR_RESOLUTION_CHANGE);
+        }
+        windowStyle  = WS_POPUP;
+    }
+    if(!(hwnd = CreateWindowExW(0,windowClass.lpszClassName,
+                                caption,windowStyle,
+                                CW_USEDEFAULT,CW_USEDEFAULT,windowWidth,windowHeight,
+                                NULL,NULL,hInst,NULL))) return 2;
+
+    ShowWindow(hwnd, cmdShow);
+    UpdateWindow(hwnd);
+
+    while(1)
+    {
+        if(PeekMessageW(&msg,NULL,0,0,PM_REMOVE))
+        {
+            if(msg.message==WM_QUIT || (msg.message==WM_TIMER && msg.wParam==exitTimerId))
+                break;
+            TranslateMessage(&msg);
+            DispatchMessageW(&msg);
+        }
+        else
+        {
+            // Directly draw here. InvalidateRect can slow things down up to 50%.
+            drawIteration();
+        }
+    }
+    return msg.wParam;
+}
+
+int listModes_wgl(HINSTANCE hInst)
+{
+    DEVMODEW dm;
+    int mode;
+    /* Since WGL doesn't provide anything related to modesetting, use a generic user32 function */
+    for(mode=0;EnumDisplaySettingsW(NULL,mode,&dm);++mode)
+        printf("%ux%u@%u, %u-bit\n",dm.dmPelsWidth,dm.dmPelsHeight,dm.dmDisplayFrequency,dm.dmBitsPerPel);
+    return 0;
+}
diff --git a/programs/3d-demo/winehq_logo_glass.png b/programs/3d-demo/winehq_logo_glass.png
new file mode 100644
index 0000000000000000000000000000000000000000..8fb8ce9147be806735c27adf9ba8714f9142d74a
GIT binary patch
literal 31512
zcmXt<2Q-`S+sB_o5Cl<s$EZ<zZ(@(Oc3XaGQ#ER<O>9-WO11VViW*g;_Eu^XEj42+
zwfBA>|8w5s<iyFzNuK+DuJQSP?<=o#wbh9U=?DP;AlB4S(FXts_%8&2<AG04-HV at r
zPk2`M)m4C-+rOOVqBr0x1g;v!9soc at e*1s`?=xt?7x6tcAFASG;e>Eu`16&t0PrPR
zPgNsNWtSH(Y at Iy;Wp`UkPg@(5x4q|cl)C0a-6tU=)Bu12G*uK0eWw03`=;1Dddq*E
z=@Av(SLVx4Tb at Uwil%o(!&K=F4OJGtzTk;zeq2`{v_ATnVVcS<pe8R*)}--;-t+UH
zTzR{OFy3)BG)xQKMwgS*Q}(0(M|Ay?)Y?fe?Y7j(Twht9+H|9FT1;Pbz0mgG>G`=2
za26PyeL<4K{k<E`7H)o6I1(GGTs#o!fre{%aOUt+OuU6FE#oQyT4;ELx}2^SQn%u)
zTXd8LbEOIcdZcKElhzQd!|ewQ4Hj4_9BV|Vh$~B*2Of)Ly)f*l23s2huE7S$sn>?1
z<&X&-`SP;E>XU?I;VjbSB$1s|vM+e)?3Z;6`?j?q4mzALG&~%M+K at la-RbmQsQQ}h
zu)`;bPYp$A`AXrCK`j`R)|I)|h6?f57?fxUbIl?#iNTyI@^~s)!@{stUzQ(Rs|>K5
z at X%VNn#f4Ewz7ujXAl@*rA~T$q(*m^?F4LS=e}i3?bsZc318Z`h^5pTE=;4!2=j=H
z6 at n|FVPU=X1hWH4m_SVopv2v38vp}bNj}HoQ0wPL=(!&G at VCLd*`ROb-(3(vH~`%o
z5q~C<tVSRc1<Q>id%ir}1w1G`?djy%`7BpozMSEK at eu53OX=_!dbCY~gzK^-DE8YR
z1`O5OdhlxUzOWKv^XiAOTx~HNWhXr>ZS|N5=OtqzD$Dj*<K1FA*3ce6bYEc<NMU})
zBfmDYcgzu9*Cb<&kV=aYpb=q_y$j3QZ-L2dtC}k7Ue42?Ox#`(vKxw`>K}Vj+_>lJ
z!z92jh^DCbGKE97FN|KcwZD at PRc=}3Abh?YObD0MUHBTxUBP{DkX-FSGDIV3-AAkZ
zu}OBJY<GXk`u!R=H>qCQz-o+!?cH#Viqd^Q+gU=79DRsY>&rae5I?q;{j3#z)30Kn
z0E^duebIpQpxzCeas1CY_SKpwG`CoVDf}l*h=S0W$Jx-O-KW#qCt_IB at 0}urhx&US
zDj5(YTr!QY;%$qr_foUwcaPuqT7NqSDzE at bjBL8=oI(}GS+8Y=H7K+J%Wa2iH8i at 6
z9tLQYMA-JN<-*q00?F->ww?g$p+VWxhC3#;PVL8A(@7soe9hOggXL3sjfJ<;zWN?K
z3s{qxS46`4su4w*FX^;p_qyzvduci+TCcrqjPaD<G}iU&d9O#D>oPCA8ci=xdlh;j
ziRm+j<sTX}9e=IpPEu!*S~+l<{YLr3Jn-w8)9P?`LS6ILi{bUCbX!{f)=T#Tx(KAt
zrpbKF*}<C5S-pu%Gv&#AutLE6{N0t{9shZml|U-~r|T-;wqDW`QS*1bHovrLI>_AV
zI><U{3Q4#+pJ<Jzcdmy7UoJ5xu at l70pFe*Zu-7el@$buE;PqzfHIYlu!3QDh9>jr6
zx|9dU<1(X=C(Rp=d?p&_A_Ng9PYDI#gAyykLyUp~!yfjCnvON8eOdK>TH$uIF$pQm
z(BD_96c3}zrLav0C|OKfO at DdZh7ObAVnZQn>^gi6 at W%1V5QceexQFwDfx3pUnuVp`
z2X;Wb`Ab;9e3~9m2w=Ekc1v^u2^B6ENUQvg9J<_`%ua at bjzu!udT7UjjGsJp!<_?{
z^KR26_+omm;^w?!O#buqmeuNy^wsl`5u{(U*-DU(!j-7m&H2RAoc~Vw%*&%+PnP&x
zd<Rm7587}@v8PK3-q$Z at y(Si#4u+=xGC!-B5K#!?D}7wv;gNNa!OeV97kp87x+>Ay
zV8V(~+{cEIE{2n9W026!&d%p`)7T8Q0b$QZQ#gxjJ1#ZW(foo=Iy2sPW_g)iTXF$b
zX4XuXwPp!kP)>@~#qkz4V`+atptqaa9KiyUKl`q;IC at _|6$yJM=9v1kfhz{tE7T#_
z^>xDRwM5ebapR%<Uy@*&$41#}Qbt)}B9XiUiFXOAMOEokqc6xfE=(V&1wMEtG|C&2
zwuaY7e_BPi6189JnqrRQuu|N1O<xrkA<rE0LEi|&s^<pfrcH$gVmzETjSUOX_n7l~
zrD|2>iuxgdA`)BKNrF>IVM!xhaZx+%jAQLIwX^W?gR{HY*r3FGld}2#N$XAEnwyK?
z*oTc)s1g#UxMjELJN70gI>L8->GEK>x06)i@`qf?)zvmy<Fk3u72V6 at ciP*nH$iX~
zLC4>`Gp?P)li$2}YF|u8_A>b+vab(|sw~=}0T<KrJtp(#kJsFoZ%%t}Z!=P9w<;m<
zhpaaJ(ExuVf}EVZ?|`B8=4uB5RQL`$3JME{CMA)@#>X$(DO}K+o%KIq1+(U;+ at +hZ
zZl>Cw7~Nn~L>7?QD^hsro67R=PJvr2dpy~ZA5Fr=y9a*J)v#FGU79evjmxh6 at k0G{
zl6hPwubN+jUI$`PXVCIus0s(&%aq)9DOMOP_l`*=0&3W%Q&t>?k)#Pd8dWU0Ak$Z>
zESIp%!wI}W!Cm`UqQ?Ew<}X(z#^?YR*mlDjlRB-q%Uo<xc97qcz!|um9-pUkSLYIm
z`0D}9<bMYlLFx&NLI5!G*VDBPg8!~nz_=Qg_SBs~9*pz+S?8tm&5B-~pnY<W3*WWO
zsM3lSy4#Q6YdL8iF5tcmbqJ83pFi3l92v#r2M6wv{o*dl2xY$Bjgq`RUHZ9sv>WFV
zfCKJZV?1QiWoGCgoy3EdhZV!i({ahGuAq|?&5$CbTL{~a`t*n};^b~uv(r_1_|_vm
z&)hp((hCuG5`Z at M28yna92%;xs|>%>gF;eBHOG-6c`{KbEON+$>@5=pFiu9<N=;?i
z$v;toQ}G&EbV!+OgGpo`?BhM>Tl7Z!dBa{0{oZHqX2<?s2Z7vdYxU8%OoCTM2iTKY
zZ)W+czdB3V*MGB*)Aw5!h+W#$<@d>I{wp_?pWg{Ok$H2%9CW(yc6wN5M>b%E$Gm;&
ztK(kgP5^%JSz0gw;Ilwv9!=e{8}aty<|Oz=0<aj$klGDojunzUp0oxq<l2(C?l+H1
zBS?dG!%j<E&v`BvsaxBAmzy{SKasHk at VMpcw0!7(SgZXNspM78uv;g<>!&To>TBYK
z>rNSyv)GvN&h*QDoxPW<y>1S<;LT?xoN!zZs<nFGj}d~y at N^0&karSoR-0lZyNCq!
zDJBbWsU8!j#j_+ni#}j at p%9L$t|<x0?|w}!)2{+oOtm#?_7ek(?0Sg#IHUKBC7RPD
z=(Lkr+aAaY*w=KLYx>i)-AN+z<NJN at A_QSJt#$pzr&8C|bi3d8+U63aJXW#A`SDXL
zCs`l4Yn}c;0i$o8_I#5*VEoYhSV;hjc$-IDY%JD){(@=lq~!zx at VA^={m7D=ZnsF~
zGkJVrbR`uZ7xzm#GE)bl#m>mMVP_mE`!I=vV3A8{W+$KdsERL6FsT>iYlS?5tWGQ+
z;{;2RSP9^<UBR at 6oYz)AG87>~-bm2NV(Ndw0ankkg#E?T+7F`WwgTMlv3j*1zNVqp
z{xjZwh;XD)y(<gY3iUT1-ZmGVGuo^DwAQi$f^g)F-)6aiytY3zpMd|LftOs_^Rtnb
z1F3xVhokp}<mIn9O~p;VJR|-#%MW1BhJ&vyx~tpfr7Jysd}wZanE%`X6Yp)Zm<LJ8
zU+*P^>BsnQH{b)VyY2YaK0fuwmoM23)@WW10Y+yDaahN0okbeW)&#TGgrD^ZRkC;k
z25;xz{1^DPpJhYYf2}tp<iw-?sG#h0J9wyp+l|7gh)wm?PpCg{7z-&iR-__{s)UFI
zmotZu>HC^SGCYHbGvK!*IurW&X at fg9ttRNougttP2ur$^)_S?p)|(pAk=FdrmU70*
zJ95f^HpIla0oVL$<H^aZ#clq_t6%`fL1+v&?vIUIFx^k%FQ1VIo9q8tviZ%CIe7gv
z!-3l#Zu{RkKkTe*H|~hfwLT at N3ML1z7uWo6aY_b9##rPBgl#q+7U+c+PrQlAR at E>j
z?0;9Njayk~;LFNF`3B8Pg4w)!A>bI|d2E>;3ROVG3$cVtuH{YX{z2u2T{fD{Uy+sg
zKgk1p{j;7$?~mKR9L>?rd{oz-_btQYV0G}TR*zH#CZKl4Yr>S{(xq-%a=(x5gr?nA
zedr?L<}|^8u2GH{x*ZR<aCdjt!r6^dxNHYJII{!XSB_T((w1U)KDYgPVjedfuqsl&
zl4|0*5JA28Q=M5Xr&1gUW5rCnv@!y&rwdV}qIYDT0fv(mNmmbef*IIeu^#%HIt^JL
z`Vh9KbFckD(RPWPe?{=(zh{1fdoFcTfkVt!sA_6o at iD`Wr&%y5l9yy^Qu(d}cU9L$
z6Opx49<N6|IpF%Qs at LlI^Wy!fFT9<%1#v22c_E6qXL6Dz9C^Ex%mcTfhkZtC<+U#J
z+p;H~D(~eeA?qjKX*wgQ&FYnHhp+U&8WF`i006yUnxaR%mU`j<OzYW)*7W^@dTb~W
z03^ttbN&8o>d5b?ECl~jf4M&Z0R#g7-Ur)RsGT!Ve{W~Sm*4TsEw*@GeP+`#Z=(D0
zGBALaVy5`F!+#=F=!TL(_Wb#Y3FCfmh at rd7dF+wi%dO at 9H!w*UWlYW|sfG{OA?#Bn
zX+X#T<HSotYD^W<Y(@$)iSUHNeo_Jo4psjHUgnbzCi5P{a_c7-tLH+!3}5amq}s8*
ze_|1w>iD~?y>b3(J1`mVUyO>LjnWP!&*SmAwRU{wuDX^ZKGz|)Io~zQ?ifmtP?wgL
zCTm}OI0yt>TO{UB9-a-K1TuJzD1IH at 3n2{vZXq`mm&g_DY}@*_VGcP0_wN`_B(Qc}
zG4+hmEU5^eZaiv{zX?_||B-WmG;F#dS at Rd4Ku^XhQ)}j=KB4A{4T(E%Y+|>1OY`a?
zcQR7d)kf3d9`{SS|5Z1?fp1TPrfXkBQYdkE8{1_ at w4T0hEuQHWzw=+v&BeS7eD4;+
z2(P?#qGq#CyEq;GE`#gxcDp*7*f|olcw*z^^n(Utpd<II;f1FsMcteq4}U!tDhoD3
zNw5>_mAeEIVQl=E{Qp%MRa!v)hl>*+ at 5<kt4S&$Rj%JG&{5f-ZcHlN?8I^vp<{K~O
z_#2zge8mO!76FWYjCb><sn6MfdCUEs at 57J!Dmt%4V+7+Fq*N6b)754-ou|nT(EWv?
zQ8etG!NL(qm3)3 at 1AHk)Der^e at T7k22d3uYc;D4noRtEgf3~9D3tQ-2ObC3CB-V$)
z^s-nj5#uMB!fQNcdxQbUU$V=a%!sd3f;~y)Pf-9?RltwzmiymmOMh29QCCyj9Z at D-
zNHNfMlTW~B@&SCa=t(*}MW^HzEEP`MNf)#Hx7+`RX~)iWuXO at 93?#Q|#*Y0At9kIS
zB}G|Kl>K*V^8g_l>*zeV<HTn%-!rMTjIaTL)|utifiwXL^sGed*+Zx4TH at DKd>wCe
z<X?SoX`yY|SxUao->!(yXcL5^N3n35;bId{ae8Rf)YaW~noq2bHh#U6aAA_)d!>WT
zd(96vspZW|1<gAJ&GKs8_<Pvp^UA(}vGWB}Ld1qOBy at v3E!fHH3KCI$4|ffS<~<^F
z6??7{dAa|R1WBk^K!(jLCZxE+xN4}W91%_#hpkew8^`btj}UZ*%H$-TO8-5%@BwS2
z8(8x{oa|4}U;m!Do|<T(0$fKmIi(T?su5tKK-Xqa-@!$8lk3P at ZhrwmlfmPMkpFDw
zs&BkN(B5mG!=LJVyPc#mD}Qdc()_f8dbeRX(7B?3wXq*^3#zwmIc$6y&;R(}AD^)g
zbKyh+O~|4Q_ZXZxMz=1q+v2ucC=f^>G3UePT)%(^pc`j<8rHI2lLlaMJ{FvgWnWVO
zf<i(eo1Ytpe6OwJrSQ^BU(yaK+ywA~DOHDQ2%_ta&WCGKSjx~utG`Ztsz;w>@{J!a
zYRA8QED>T9Y7MIionmSF2$?=H_=kprZM!N_cTw;xgSlQ+QrHWrwNfucN#L5ApI!Kl
zJM!Lah=A|+`>t!5-qPk)485m=E<x4^H0?t0praWMAbB{VT;;Q8rMwHl+)|@SopbkM
z_iG41FX1eTP7w#dZNSR!WkfN!!{rZiNf$zi_+1 at -ha&^753+md=XN9is|oP#e<(2<
zuFm9ZGj(UZs|&W>a<M(7zhz&Pc^o?y4VD;eKTk#1+b3pHD_0*`Nwx^~mL%0cx)>17
zSs^vNmR^&`bT^vhc2tMB4Y=Eq8m0g*y2VO>yZi>a{y}o$4``vECqwU5MirO%A at 32}
z7G_Qcl|RkN?uobi?SA~nZfQtn$Mc%1SLkv1f41+v!jY#SBRIQvfQ^SfLK<A)Lwj9%
z45$sPf!}4uVSFaFU<K9s+g5Dt65 at 2L&z-;h<+xl6zP4KlTFdYt0pIkccb7m3F77mm
zA*L7qM_Go|(R at y)x?V(3J;L++*h-Lt6N at z_Vb$j5GmciQQqBxPQtD{qMO++3K#A8s
zEU<pf$+05R?M8;r204A at rfx&=VbH|vqoE}K3>oh^DTX>Td=Db5XP((KJNY){dgk4F
zk=by4IHqGg_VFQrx#fn{8GHs;j568XaEr~~<wkYRjG!s!iw(j5v6Z#90KRp;NTCMQ
z8Gj4Y=x}UXkK^bi7QtI9LiYzB4;9a9V at x=lKlW|Ys-Q)XP at Nz`otrBuMu`CTZkH%*
z>v@)v78+~e+3HDMenhp0pFC^g0-I?xHVy8|)DXqc8kOLUKjPzEx-0yL8eJw8sssl^
z69HmCsn3UpAH->MH0$=DZGVfhx5EoLGhCG-ATPm$f1l+xod|Z2Df^-=kCZDgi+UeD
zF at 2O?s|;^X2s&g7xY{(Ix2|vmMeqNj&gqZv?Z<+`{flElgU8yn at k5vWB`&3VG)k`$
z9wzK?cjtw-u`$VdrN8G_sC#z(preHG8mdtuf~n7aHMHWW>_fSqA3v$W9lbv#d{1{!
z at o^fej9=*m-M<=TQU;a`YuUfnFB|#nnEn&Ep{(#x#a%aU4U)_9StMZa!G>tx-0bx-
z?-Y>rGI$_BY0gpzsJ5ahR6lB=!i!VNjtiTvk1BdqsZGOqDw;;mvOsVE1NfE5kfgOm
zT;LNGwu7-kTBYdbIi4yVHVm(3qKc4_yqw7EXx65WDIIJobb!Z)!*}EP at oDVH_t-ke
zhK!{vKJ9GA7f8a3 at BLYk8@m9NSK7C~k at ghA3Dh`aNg=_?iW1u#Ng|f;d#3lIR=)L`
zuYIBeWH*ZQE1&;lU2EaY^0A80I|U6JsBx-gXC!fSUSAWxsobRb at __lZ@GZ`lOv-}c
zUcVT_bKLh2m_HGcm5rqpdG^2;!D at e%5C`n at D$}X&=F_ytE=)CC94EZjr(N9KGfUAg
zJf#Zhaqi|5Ta+~b636{+&fRl#zd%^(J79zf2-di_kZlShJFy!oCNp)oQW0Ei1uZFy
zA}2sPQY+FO{c;d?XhN`bq2^Z-Ppf*FM6lV%$F?|?t_w=Mrr*XbVDGg9Zmv$2p0u97
z^_agJ1a!6bzE%Vh+hqsVrW+Km+*Sv$6UBfw*wIC1^{u_d^W-yZjRDNY_%Xr^c7h;K
zFoYpPaY$v6V8Deom_DHb#lUSBOlw-cyXvMRf5!g1!aQMb&rPrg6wsBPfAtwap-4%!
zvXr0@|ETnFi2k=}dFJdDsp=qR&AQjQw4FE$(j}L$aHwH11*ZRUp3M+q;gC_QPxks5
zPP;8%(7pEnZK94f{@d1nNx092F30G0xeqZq&JXb;#Z-;>NPhO9)u{I6(1u&IRl_Fa
zRU;Xe!a9PzCqLFb(8tBhU|Wg2E?EH$J2x#KFvcFd=<NMtmmPPp-8g*45OkQ&oSp?`
zfvpZ at z6R}zKNp$8nV@@h+Sqy_bE|7hXm-3?4l;3kj~o9Zo}}~zyV_olM9WVaoDXfD
zgJKg{#vLDg0Q;*VNbGaNDxFBd(($y51Q=R6L3eKJ{jD1!5PUXJf42Hz4 at ABp?gV}?
z+3Ygh at Z`^bCeTT{rrO at diR;SSCsts=Yb-DS?-;s_&=h$8tzr_eDu{-r>>DUyefO)^
zZXcQ!x+kLs{>u`Cs?&Qe!vr^*tHZwr5#w2nqbo&<&;to?XC#+cGmf7|%(Sl&lvA_a
zqNexF-_3lzVND2NJS77{7mv#ki2U84guqvVKO1~6me^jzIXLM)_E18KukF1|W$UXo
z-%~8Uf)NWRnUbKC)GLr;y<7bUm6eryc+z at Z1JB2@#nWD7<j(Ib_0YS(Pz^N97n8k}
zmYsMRpy0bzi&YN4?tvO3yB%~X>1RNn#HUwgF60*8=;u%I_#2k*9LUZ(Q<pxenA at 5!
zsbKuCDUgA8086~i_glgL)9FFWT00wseBqspJHkqs{i~;M$6;iTI)yRl$}j94C9FXH
z^KfWrJL`^A9l6LgeRmmpmX)_G!cv at AKP54UGp#&TqXDV02$!;hbBmp1OL;s~Z6IJF
zxp4WOe3x=HJ9XcaF;jhdXYYr|@QlmBFb;_%kbN<;<~k&`h8p%*3!E%#Z+=wxP8&4)
zc6SAD#fYbI5a`-=o*!+3bfJ#D)l3H{h*ZBRPV+4{&{+F`IGpg7=gDGD7)b}1AQ-Te
zzW2y<@8<?>$WxGjB5yrlHa0fUOQiB^W at 7SPCiBRiO^qj0LUXCkZL$sSbGJ*p!CRln
z-l%4dSi3-F;Va4M4&xM>+53Nf`t^nTYUZUd;hK(jza)}1hRRwd5Yy}m+cvaP%3OPs
zO_uIno%8 at _9b<@#wU1#R<|A|?n;XuO^T+z8fwp%g4+1bd`t;=CS?3)6N~>uSSOb35
z?{*N~u=hz!0e~tsvo!+rvc;0w+oM3hh{<g at o^t%TbK(ZJx<$~CB?1+%{8Rs}uc&Y=
zXn=XAm=A#YVti|}e~@qy4 at h|Ria>b_L^ty$nLQe at M)_f~xBpS{wAyxOPDr(?a}}?B
zcg^<OmGjkAqBO%&W?()^efGIw`~rj}owjphJ`hUU11ujsjg4?DH59i?^Sck=diMBg
z>F!SI1hM%adK~uub8F2{kpBkV{bP|%O!Mn|4neCDJj1nvpwSk-nw44+bX59m==z$s
z{PBRHSq;Rf!Ts*`w at v=r%2&WAz4&l!{BW!Fq<N<sbe>yIy9J<$jJaMos$Mom*K=Mr
z6V7#mo_}Yp0NG(2J<9+Wn`shXtHIhgk{Em~?f~$Ns_-(KOO-rcnIUI-n0Ka>ZF&5S
zr`E7izaA!w9F?)~QHAslWnQR$GMz0aRh*GgjRPc}{ncyYu6w^EFLyhIg0C;9n1fAA
zDtW<TI at C6;E&aD3gxvO6LKgd}^s`dwuc?YS3?sy8zJ*Z<KI5|#N5jnATO at zP9d&Uh
zlI8kp{)Q1W6^&W~q=uw7d4Xy}qCQL3WA=Hlj*;HlzPD;^5e(<9Td~q~F}u^VzRm?;
z!BQ>;XadujvbY;(@`q$ECS?mb#l<|jPucp%{KrMm%o=)3?1?uUy%ea)tg~cIZn<LK
zw_L=>uG}3jV_fvY%6lCu6D2V=zxu`(U`VKaDyy}x?SskhoY}Iw_cK4w`_DD`N-ifV
zJ5a7IztNd1y}D^+<;?UPHTz3AlgZuI*9X7en!hG~O)by^LY8!xwd>G=FVpoN^9>o`
z`rFuU0rbtFK<C~&8Sl@^|NL&jiYX-fa+$OK=(kA~SWyld>p?^Z`jXrmt?wEw*cifh
za3LxnRX;PRbTj=g(-8Ja2L^qGU$0#EbjPG|k>1L}p)x-!`<<Ru&2OZUb8E}Wq;5>f
zhfRY9#}OJ>ptD|}j!m1?QR(-62F<J|DPJEP{4%pqcbC($@74g#aPUTjuoa#>@tvNY
zi at YU3e|AERF$z$H<F$R*e#egs%CiacU^xyBj$P2&JRylEk7Q{9H{1%eB8+ODCw*bj
z;Hk*sDPGxf32uBvC`S9Yk1e6=N4f}0xL|oNXj?puV6MFX2q1^}FkQB(yEq|4Qu#ms
z*rI+UVK2RLc-?3f9Rvw_NIf~>Y)Sd6DOg>$)!-SsA;}4s7v4rp^TW+wILe~_ien*&
z3Ig|N4G0cl6cUD8prjX={$8=|{toxBaDg%2PY0Qu3lL8$#A0Riw{ue##|?DK|G~!@
z!-BPh?S>cvKzCETAbpnmRv<kFEi>h}xIIQ&6whR!H1zbHATdVx9;_~iRrtm!6OPtA
zBcA+2^i)S`g<|IA^o#nnEdP<Mmpqs8w-~xq8F1zfq6D~1nx_lkQN?umFR~4L<nRIZ
z4B}^^)>h<x?Pp38Lp5~|$+-tHonR9~<#0_5;Hko7=&p&VpL5}PC%?CE;qs%_I`V^B
zeZ;Y^&^cr^2s_3ZKfp$@bmWr2?fQCqlj7nO*$Fzd at q<cn<0@#BJ86xwsOVphPklB1
z^6b_up&YJba}rRB{xjvMa1EB>sd9^-bIG at +-)(VjHOU7C`EIr8UKhE}1ON4BWhIC<
z(16APkN?Phz-IqyP5z`|=n9lg&LTZq)dTz<&W+2-_kq5%gj)rQc-JS at JL^3k_gbKZ
z2E)Mkxm3Y>#tk3PM85x|vzQ+6ti{C=7(YpjjSYpswbH*~l^%|fVLv(Z|M+h=bhBc@
znzji;rpw~E5Xn?(57^3Muw$ub{lzjYzX9_9w4~~bX}J7jsyeB2j;|G(nI5P@@@$fe
z@#Tk4K3V+#EPznFI+J;rSKTGU9yxuY_XV()lPSKw==<)9x_4=0jq$bWed at 4N`F9)e
zf41DKZX|j8Dp&svORX^+<dZ3Z{ul1Yn_y|<CLf`A=?yLePLj}^mxbe5sk1BTw|?y{
zyWHApRntQaB5Sk-8el1<!Q37PiP#Nwf#TVO;QP^Pjzr5|9LGuBSo3{>W{TU!zk5qN
z^Vi394-F<jE3c=g2LNt%NpCP|Er*34M}fZM-7y`7W^h+nK!nb-6Lp?V%Q7znS`tL#
zf9 at O$`uo)PKiA7LafK*uDzGbY!^pc`AC491IDT9=;(Wq&F_aWiCXe%<4lT#y_m<C&
zrL_3{ao-WTd5T&T;eJ%c^tsQSn_tl>T<o`^f_C*_yAA{NA6!m at PdjyqM9j~jvL{D&
zizC#Thz_Z5nz6AfZ!>Ogd5ypMP+wQ8oo1RFn(&Nb<CTQSvmb3lX1k$wa6-K`bH+P6
zvCzN0+x_c1jup*RJdexJ;MrsL_aUzH&%6rh8x5X)+T7hNQ4Cha?JFl06M+*xPXj=l
z?54HL2noJk3+~DEo_hu6hb4%0lIQFBZnxDAG+;V1q&$9D2Z5&5doxnGgLbN+GZC`}
zHKyw=m+s}`t#=H}>fQkiSI*R(Q4HZYr2gXdM~b>iSbqxnT(}%5pMuK38xzfd;WSjv
zCn&t9T}pY#qcS4|99F2Zk_sa!eN>*Ax6U4(M at 24Tjt<WCqfz(05)tETls at r({I<lt
zRf*ys?~oKqGCbx%xR$+53eFegqax|2v~Pa?a at -vYZlD8KOCr*T82Q^q!_wvxuUShx
ze75mqFYif4jEXD6w{_qL(|Z;J7%|0m?hCm%S&@?NkH-fSdk at S+zOn(sCyLyv(o(OQ
zI1s`(d?`B1&rVFg)~Is{nTC##`)Iw^5CS&8P`{dpOZiL;tJ&WSekhh#Em`)mBud+u
zkYC|P6C^=j_UMEEUhqvT>B3*f)`ax-jK6QqY2#2%mfDpx)4}faKJP;Ww|Nmihi}$I
zBR6yukJEBdG6&LG-yOwKIcpcm9h<&={(&~WkJGmcCxU4!?5n22DVxYQ#5Z*9&LSfU
z(#$Hizf~}ji3{SQZ5=DWFvTK^l6pViL9lbYTAYEkeVcx~_>nXSdKL8~pOIwesr+}`
z=SYkFmU(NNi<i2{2R%s(uU|vds*==>BXx at q#jZe-NY@)V^{SXeqkBb91MJmdM@%Ce
zSj5z>$wepi*wfye226ocXT+~pMiS;D4G(6w+p83=$>wkRijd{g(IfM||CI;*322IX
z*lLP9e}cSwWhJkee;W7C5eF?t8iahug<h6gOiJ>zAO`9MODk;eVjAQ#61A*jza-V!
zh-Sd7+CJ^szwL6y=JH=u2$HzNi)G}B`2&)@uI4 at to+gk6+}Rt`VMAoG6q&VdXINgi
z?5JniVQG~G?#GDcoH2 at 5S0I2wiWZU^FR4Ub8%@H;4oko8%F9tJ7eVhB at aTGp(Wpbb
zaV0Rt_KKBjxbE`EW9qSu$6i2`(0}7|km6p<BS(an2Q+#oS3*8yQ{mV?cE(#GvctHs
z_6802K}{a7JH)z7lMu%5v47?zc~Owm%nT{MoPQG4w9Rr~c-h{}>zPt$@C at sh@sdxp
zg%9tK`D;`?{*b~Qj8{c1Q~YGCfTW;niCSzxR`stKIW)netZAR#XXCewU}yH1fdL)K
zwVd#rn=U-h>?wdSH0aKj;OI{cHh+GoZX5Hj{vF?(tb{UVmakOz9U_+U>YbQZ0{*+l
z_>~p7=fCla80U@%$Abr7A~nXjZqP`bBOD}=N8*<syl<@CDE^J<vQ%z-{IG`=yNRHJ
z`glrsnh|Ik^-H)Y?wllG(5TmJV)jOoj-BtLbCQ~~pzCnVr_K|(X!a5sp#0UxEa$<7
zwb0F&1_-uT{ehIO+KP<Pa1Di-HSvgnKSQhq{?L;iNdMPSeHP1U1A5oqR<p2x3wEf>
zi5NJqfDKzrD9u*MC_oR57}Q|Z{?h*`BEzV!SR|l}AT6YXp~cf41BR(e?r#a<(d}Pg
zTW$?+AI%pKro25MZXu6h at p&lL;Q)DwY1=Pg^)m0-op!n85uXi|m{PQ>3mSn!vzT-I
zZ+4R6`<QmN+*<d}<NjU1F&molgowicW-}}s9izdD{7F<<nw4vNdu9yAl@%tUIf4lp
zSHeERNkD#{NPCEPgqO>4Lj7(^chb6z at PMsMLp3Q-mJ}Rb;h)(n4_5EpEUsPU&Wp*!
zg95{(iI;AS92A)%T6e5v>Dfm5<b?ngS|EzJ_!RIJQ0hOREBYK7_*LA*m53hg8y(pw
zG0fD%g11e?)qyL7OCl)fS9uU1hl8P5YU$Te#bLhk+T6`gFpH#u!ptPSr1uahk7_ym
zf!CF*KY!(<poZ at h#IVZE`h#O^a#0X2)JO>o21zVfKRI{4%2M_V)boV)2d8&Iw8-6w
z at 4lm2sv&S|42t<}q1O&z+PB&}vX&|a?<Dm<jv`ON58R;EOol0({zwzNKBe;vUAVX5
z!qbwgydxW`14rhCJ-peW2CT8h at hK}0xpR^N?SLN-(4}{<_#qo4ha(1O4slc=5Q|To
zIawt|>I5d1!M=;yQccX*KXKJOC|3&tSLvA?iWdK at D1Vo0TBg=5>gT at YchE*$EtM3l
zmnkw1h;Z!gC35e)NbtD#D;5 at AJ#KI4FdCwE{0RcEJgcs-D})+?M^HyPCSz`tixqy$
z|Ace8aOzd5U+QA4awFeoEx8^HTpe?{;<{Q=`AqOc>MQVn;tm_s%TYab`GDE`<>-3y
z<eGHSrviQDDBCh^tLyy_LxyyB$$LlBo3B%be;1uv_`BchX8|PcpDhACd^*wZa)js8
zA~1$w_hKkA^W;_z;^%>OI6IfnCY1ldbWJJo@@ffkPeN>k6Eg8q{NV%EwVAI}zfLM8
zb$;RPWxP3-D+}JWtO<P?LQa#QQ-))}bUw3vDylE^D8(-)XYzc>M6nZaOJ%il+9-bz
zCtA%Z1bp(oG*$y+UlcAVRXdwGZm<Y-)yug#o^&LFbM;B)8CB<U{`(!((xr+2iO at 8U
zyVNwe2Q&U_V#}TVsPgPs#&y{H8s`O_R!728h-rnq(Vm{mJ3Js225Xt<I5wXpp4(v?
z^jOXi%ME6`5Qn0&GIlBqAbEn2`IDd1)wmh;EwQB<7-fSnTg^m|M<kwspNGT|^of3k
zB-5gulJ!IYp&3`cYo{NhjUnYn6o<VvN~=?mT`rxKnX$WW?t(1QEVPX%W7L+<RZ?|Q
z0FMTukMkcP+-Dp=fn2uQkFg%xx21&+!x62n69V$w03KYpC>8diuQrZlEpN1g#~bMX
zgL&`>&n7)bnn7jz5AS=AAKLPc&!b%PAot1Ocx%@^T&|o=6>tHl*WBj9&GncanaiKp
z)Q$Zw`04lWe0gm>9u`y}u8$tHofh|Tu-`at3?drxaCQ7o|F+Z6Bii<_If!-DfTuYM
zQpTQp#tn6}h&<zvsr)BFCtb8hwzXFqHPcfcl^r-pI%(yt)N$?}K5c^_2i|KOFn9-U
z&hPC8&tMiTK5jhb682dvmT+4oNDAR7-hS*z?E6<STwjW2xdk8fO|FaTu1|2f%2;1^
z5 at e*bJ;Oamj3pWw`h5Dimpn#k){8swAe6&tZLDk5vxqJy-Nz4_P>ziu<NB8#xFVV(
zZd2=U^o_T8l?vIjJ6T at 0bX;*o58V#CL)txAxgQLOAuY&QM*7`%Kb>Sdl!rWaCyd$q
zrDMSwBb3DP@#q^jzIgS7BD#4p^uH|gG)Uk){#}@69cj-jGiP0ISP4ZNVrID`<Ztv>
zUc*IT>ZG4FJ6%!*Zwt%VMOOn+Hz8^esR_5^R%14gGif>W>N4p?`ecRekq;D-dlYx)
zc66W4HmkoRMEAcl=R+3D`*cnB3e{fQvm38!=e?k4O=^yWaFK2qLMdqbwn_WG$radd
zM7BcJ{x*zAVzhC53gzCxQ+|h2;z)hUt>D647Ml)l_yBbs8l3;i`brjG=T6rLb=S^9
z^R`HE`oOo<mr?6`$vL_|UuAF+xpakFoGYx|yi!jBhq1t)V*)N<=LxbTJ^Ed;-f(p=
zg--MVBK*pB^v1>RTScs9jHgv~trI6)Zw7EwLleLYQq?Bo6jP|In<A83SUzhJ)UBFh
z!tUaZlUg&dYGOnc#jA-GP7ha%JPve(7=G}lJoWeGaTHjB;BslithWi{+O*XpEr%q*
zld$hn9KYpWHBEzaJF8zDbuntksiz$36ZRNf*aj^mYfaIHHrb5Xsy(1&B#Tqo5r`EL
zRBCGgmKd_cg6DbLbaNFbDMH;fXU0S>2U}ypl}o;~4m<rr5gLtA!g6zKS<CR&uu@?b
z2=)O%De$6h=FPj=Ca!=?i#{Zj2$!l`9IG$6GjuP-|Ayg+9eSK2q&KKsp!&%k#R_my
zPo9sfvAczuy%&`N6P+I_XpeqH<wPGM8Pi5#Z`+xlP%1d7MS!5;G6;32Px$l8PA}w@
zSi}=`i1Q0mQwf#q_66}_k6m`$os;%&rm-$Fu_o6iPpUTXCGr_-?qWD~A*VAV^K!*|
z=c+d7qad`G$ywFd0#&F7IOmL`>ayjxy!2+>L<G9Ep=M1%_s5Y2BlWKx_38e|K>+(3
z(=Rwz6WM3NLC1wI76G0J=;(n63wL?wK`4 at 4tHwerCXw!&6kNL%!mFPMIaHw}K>of`
zeII&s(dRE`)6C at ep>DCr{EAvOV3ri?;V|Owz;f2z>bi0BjG&lHzMwkPpnF54B;2dj
zUR5sDPd-m<GcnE?e?b2`+-VfNNwpBy)swWTurQP^C4~9UDSNUCG{i$Eh$-uO_0j21
z#~VC_i{D~2SDn at xZwl7m8)yyqKJ-B5qO#1ca7!tSmV5b$>n9o4zXgz_KC`%jpV?5C
zP2gw0Yx_7q7v(5$#(8=D-ti}a^vK4JJt>K0ll)hTY`PVWyJkSfg#kXNZZNqmB3Do!
z9R9-UkwODwD@=)&r8xK!zk-}ih-VR$(+^)iwy2n4SiV5TvTYv=I`$wKnl6z}1k^15
zRwu6oCahLowDzzRwZfya4g(nWXY$GTjQ~Xg75fFw+~lMDpTUY;(VS>Q8$E*kN2H-2
zPu~}2J!QRQ9bg$ngo~)WF_k?Yo8B#TF^_tFrG~)&lKHe%S9>w#8eUbb(DCpo+(H)*
zijnCam;!<=VirS-l1Z_hz2Cfa7XHMtI6Q-iSJx2(RsHTHY$N&sgYd&nfSg{!dLg;n
z$o14R=k*%ShaRjyr0K<*$(Ow@$a3R^B!A|%Wb&-nwowAg{(pp#!*48`xoYvqwG_n^
z at u^T;F-g{{-Z_<z{fTxnaD4HSY*EG}1>BG4Z;;y!$9_&{vz=&#q}f1{WOFV#vJTbV
z2or}gEa_@>EYl~kU|W)Lg>x#i{nM4IXURwki^T=?_H&^;UZIfqK|&{*(71m>I2LPb
z?<ow$p>(9Xp}^iLyZ#Uv at 4KiWH+2@{8=~D<ML`ll$b+6}ai{KQ$EalD50!_niUdz8
zZE4JE;5B2llfhluglO)N)eiX3Yi0#IH5QmPQVORUp&=3-6ke2VlyKpEN|trqUD3{I
z?W4jk=|wr;zYvjGO8pj3Y33P|WyFmNw}_(R&C1<(2}ahV1$@Y7q*j4;Iih|{0ql+w
zY>d;90eh?xP~>9zAhT0JQl=09eax*ZhWBR$?Jx*O&hnpwhfgG=OKo<19ZO6QI|T1Q
z+bD&sX8S0D-PS at cX1OG8vLnR83A&K+XLt37Qqim;K+?`GNBvj>!Fhtu^(M!Pi4$v&
zN7dcO$yvF#(7W5V)!Gr6Jx`Fl3cnJEZcyjS0mJ>j^prMpSs at 0cb=2YL;_*WGesi+=
z$tOcj-A(!5>931Frr_z`3u(LVA&yqBRbHm8Pka=q2Ie*%x}xZ_DBd5oj<V+#|GpPh
zVo$Aw4jOtfLs#5gHi*<h3(ZJg&9+4fV+OVa1Di~esRtMv#Mz`|^$Y8F(bfgVk?&S$
zwzWfXAwF1~a;o}IN3UgZbVQ;hRi&jPpC3>;%?Za;iEUQC_{FyFG967K{ruuZVjJ_j
zHG at a3QRKLWjs!0m&5Jb at xs-KPVEaveVssJ3v8)2FxN%H~Hi#sC6Z#>u_HI{dxlbzK
z=Nn at j)Jt&jVYf9&E(=N{@bP`9#;ZF{MUbC8gBF|&QN}!}ogXCVt at 22-M3(IdQ$O}C
z!F)4N_wTU#k_bFp5F%07RlEW$>5=yF&zBy{Hv95$)b-~}d}G`@g(aJjYStA2EflPS
zwgrjLP|#gDW{*%`HPeB088W&pfww2&L;p%E8ABSgo|e`kRV(iBogK3t3Rq~rpomWF
z$!|)kl>L{2gpxvPueVvSUKMHz_XWTF`Yehork0Z=7Y|t%ZOg?i{fH`}L*kGxEg1#$
zDZXoXF5ffZ9NuS3m)JWB*yzRb#*nQrm?g9R(2s7z-{a;w!q)u<2aPRV1*N&IFkDmk
z6z+YRNfns*PyG7^lNyjClgDiFj2qMk*S7HjT1SD9ds=4Se#4Cp at Z*FM3AMvH*eR1D
zk=6YRAzW;_DnvC1C`lWHYY&ah_XdU47lv1Pu+8GKR{-6gH%haGnGr0zT7i(EKG$Jo
zZyO3T8jIhWy*MG9e}W0|`^I3t$*2UYbV7FSefCElJBFVY{Nexcoo<PTz9b52#BKeh
zIO5#t@^v91L{y2yxA##HAyg;o{NBvTTgBa!iIZ>)=RXZ}$~PdwH=rG#>ofH-i)9`W
zy$P2FTD2kRKUi*Fmaer=IB<9W-`P6N;=>P#9?sId__U>9n7+VkyB3;~;;eccc~+Q=
zI+8sUcUH?<dw0`8&LRzI!!=4B-~zE*Ge%Z3QI%|85_ecQ{o>A_`?tF{^}^RvdUrZk
z6t7(OD~mzSxQ{XmmRnbw=M!f^-bMeW0q&@;QV~RaFKV1gwF at f_(|e;;uZA&<#Z>mG
zMC@<$<~d8kmqQJ-xT=3{O at 4cUus}Sh;-<H^*`WnWnK8PAS{gz$Dl6AnJ7L9Km~J7z
zH>Tj|+ZUv~BN;l!74zUD;0E5-#3MGFKwl{x5!a6|PxS}|5LoZ2-6(0e^c1`XoLSxt
zrIJ;sl&v;&h)UuFbk?U|m7XdY at hVtx=T}lR@<UPD?C6YMqs|Aamb&+7U=IBWVjj?=
ze6GE=C3*3<SVeez#=*zC^-0Zkz(0mDdxZWkU|tIXwWVmoJ<qqMd9Og)*~^H-VS~?f
zU*zxE7=>{L>uYjfa1J3kbhA2J3+M7Nkz%Q-3Y3o)0xJj1upxI$ej1+g73@>@glH_G
zV9{K%;#GMthZGvhdxCrs*WHR4 at X(Ze2)z?U-nfoM0vkC$z5Y$9kwQxU0{hSW(ssax
zR|1<&3=<#i%X$qwwLm|H^5R&iMQmyS(5tGgzGMpgs}=jcYFH>T9m=kMb|9%Xm5`_^
zq>oEj&5JYfPhmc4f{+aHb-{ZIE^~(zE<FnVV4yhbwdAaKR$(Pm^!};y^$VVWhNXnm
z$lz3gF?~X;RDBq+ at V5i#%y^FHI9Da?VmVP4ljnbP&s8gfyL}LosCN7wA}Cp_jdK`_
zeobUiL8`;?O(Ty6U*IX=KB8~TX2;;08pb`G-AgdarO&O1NPUKk*;j`rS@))#oJhYo
z%_IqZOb;6S3Mq{Q|NL6Yv013pHNJ at TVwXL}LkZ~!Mb}|d%&SU49E7BVZpvMJVya(o
zmBZ8j#4KNZ7q-FyyRQT>+Sk9r685P{0S^66q>Hu?t_6#a<YmJbp{0mn^(+pD>#P{)
z9mZ?UzVmy8(d3m)li|vszt$L$Ggbw(*Ftcb1yihR$_ar-Zvu4nm1Jt_D5t-qyd2Tn
zzH at l5pO+0Xflee`!w`N*L*d1edYurj56kTwBVRBo_R|`TQH=MsXh6av2*%5azl=eW
zo~_60paG-n&^4A7ApoT#Vq+h}t3}C-62AF(j~MxY4p`JXwFH7SLNV>S^g)fptz*J^
zz at 9Bq+c4f`ZB*4OXD+`nCtGf>E&#c-V%pRupKVH6$rk4Bi3tI6h at eyy&!JEb$=cW#
z>OK2vXY_w0 at X!J~IVsWxp_kvb+rX10Pnmu8?qoY=sIX)FrKJe}{ZM-=bekb}Fq3AC
zVBILN=o_*2B&uQ*5J<VJD1sj6Y9-ppP3~>%Ya!bIRS0qZUJ($#5%_{lcYl{-S>QCH
zATnCzK at k#imqONV-FYtZsjD%eQ!TDobsYlj%U4@|`AjQO3nF_}vBNf3Nvp{a7RmCg
z=~Sgs7N1(_5d{39M`#UmDVx&N8y{f6-Sy)bVD1h?f@!LZi<-1&dmfQvX_4qYF`eAs
z7VoYDlsA}p8&YPZ^eKB`&DyCC9b93>2M^MFOW)`zvFtPajf`_QF0MR=iN?(L&6PnV
z)!NONKTkw*Gqj!H?24*-2i)m85IiXE#Ed+VyO7#{;0C=z0MId at V%kRyLqn9VPfMu#
z2+=0VVNJDAs0rVxB^(^d{6d5Wc&})-JW>{<B-fQBgQbtc>(x4fOmTOg9Gw>MuZ0Q&
zu`ILVk-Ya`H*BH}aG%@kgkVTWECvZgm6gPh#jL;-p-{s%w=SHa#)d`EKh-JFmccif
zo5Mms1^SR85wnKKDE+T~r`_c%8N%C;eI$uJSDQYFrh^nJrcg;(oy0AxP+mY37B7v+
z`Omjl;l?oPor7e36?_zMwK1s;z59wBBKioVbqAPk*_L}LB*;Fnp1Cjh&u_9Wy_nx2
z!=b^u`pA3qmPT1T+UQXB<e2Q^i)6;h*Az5;1?{;MW;}_OH at f%>i7=R$R3DMD4^uh8
zMA5w?$`v$eF)raIq@}v!bqpDr00&i!!^u~`d~{a{o<@@r?}Vdc5KV{30crd{LKKQX
zaVQZv2uDDDEV<~tLjeNJ_NnBQ@(ToW6Gg{~t;7chvLP{g!T7{uFEO-17;O#*KsKM2
zfr&4J!anKsjoocWhlSW+PB_IRF*2m+JN_yWkaa1h*2o)kYuLs|1SL-w9&Ok;0|o<R
zu+e`2+#@r-JQMX{yBGo_2b8pUIuRtuaADb<8Zx;{$tg?BnR+=u8i3Slm%_i#PLg<H
zy^II{$F_Ntbi(G^jeyy#w7W#WBO{RrQWhGz<gOfW&l_<C5a{A3^v at c90n}ICWPy(w
zC+ at 1UWH2h&hPOJwHUvZVRUj{-i;JB}G6)d`Inhfr1Oq?o#Bs$&`^-dul{pUw3Haar
z>=<aMAR4JPEXz$Z%GG_DPl9ic&k=`>{Z6%@G6-K+ABA&SCvsA8VvxEDiF2)EsTsf^
zk*-C~N0y0*X=mER6v<2dJvqHXd;`5hGQ+4>hW4#t#Vy-?LJKMU<q-~V-SR>y26|X~
zkSh#T&Ab#;C~#U{?N|+FVGXH#A6EQ}JZIYX>M>E)PQFYv at qyi7TWn`q$QOq3H+|v*
z6f9hi!*k5S%jVUmUMKbn89Dz9^9mbD#KR$S#!L_nW&n~6G9^OLyQ<WA9eV=aI8&yP
zM+Y~iu{o*7jzh)|Xfp}BJecmoeJV)75tXm3n2*e$(@g at MN-Lp5T2&y3LV+L}R;P$j
z04BefM22?#A$1jD5qck?2ybX&dq{a#QfV|H@$kIwJkUnZ at DLx)lFhSAOjAtSTFw>%
z9+qbKHg at T8>9x)c5KeDhwm#>*H;9AG>mWlDw+O<cRTu at 0lnyn!X>==tU~`*c1gkSe
zB{0$I2{z!M(~ukZ2Vu#IYC9pTnT9KW|FdJqV4q=et;d629mcbJU<HXav9J*0L_N|2
z46Y!4UbSWL8f at L${Y`g^BHKKmSwGguQmp*X_Wg)r;+4(1%jl`fAmnh46%DUS_V4iP
zVuK(@Tj at fWtoCv{E{)?o(EC)zLH#SKad1p5DuqOnf$OdVf3vLe9yKQ)f-}YPEGq!I
z&z=;i45x*#S95c1eiycw+G5)}N<6x-_{NF~e<0DJ>jq^<t&@8HXhWLbsqsA?Km29f
z&;N-fU{+X{^ymx3slrq?GDZ4ArF^YUJtUd&5DSCJK5QrdWf<}7o-W%(A22Bk{LM5J
zLl5JM)>xPi9y^BU#{^X*WC-#4{3U9K3p~cG5F%n%GTKD-GceBKpaj29zAO8LtrK3X
zPE3_U9}yrXGvXML^J#oN^^BLoEQJSp)D+_9j4mly7e&3L4J}UBcv^Aj^%L{(=x(@D
z0j&{(GMwbM&yCu#7a at vQFwsa2EkHutfehkNnRIA(tozAK8)1RK=g$b+jkZPl;%O1U
z)>OsNZ=qvm=JCK2Wo4uHVWpNd;rb(j7zNRSJPgU at 0?DN|zL^O$wCjLj$C#-_s91UU
z^98lCg37~U0j&V2-WWcB)W3bDjfXMB%hSTjQXn*}w`v&*|16#_772RnHo!d*=*Bmk
zPGm0KMmoDto at lRYW1O)-AX&9&vOO^Vqm5lLYu(*~*9`+oFkVfR=Uk~i$#<gl;)W0q
zd8YV$_!_>xGa{<T8(iVxQTRF+VEos9<+}SCUAJvMv0<VNRG(eie4_w>sDE!pcz)Bb
zxY(G7VbsnZZSsFT2Q%J~GK8ul)o|!ll3v?^>!c-q*jdZ>&7&V}55hvO<VT&!h;7`g
z*4vRvq4AcwT&=8lXImsqsT_E36~*-K6ZBBfp#Pv#WX at wanDxJv*E3QIR`x%7r*<@W
zrkV=L7zo1PU4vgp54^!Ewr|hcCa&xc38Kk~nx$_3|5<=v&TI^HN;Pgo!dik&KJt-S
z!MsMPq36O+*S;xNGT-msIY~M^*WmQ;^OI{ZANd5=RV6*PL$ouemS7~tQ`K^2la0_N
z{4O|dD+J93CpeS7K at am2kX&ERV}tHg;bbqy2TsZkDux4N)5$*(@E11BG=TnpRQioF
zBk?dp=HMZB&tA at -Sz_b|@lW|n38V>ijW8wf!wU|mhJRoKnthm3Mi-;Ynh!j>b13~-
zEaw-LH~^Czqo1r_>YV<)=ufaXPGX*Hx4I;m%B=6Jl?Kx#Wrxd4l6nsolo3A<XACfY
z2xj`Q0dVz(<9Ckk7-jJdv9i>lcMsCfaiY_uu5x{yGRMPCQ4nu<Ob<<x+Q+S^DWLS}
zC4}Qma|c`yul>>b_J!~XGrv}7Rvz4cE0vDnzvHS7zc-&JQp?bKj8NA8T!oV3Lm5kd
zDLT~K-{$(I#|HG!tY-ks=nF$Z(iH&?MwRGzU`_!+gfrsIw&VTtwbc(vcd5{@G$mIK
zY6k<tA;YwsDY^nq+`?w2QD at SI9;jp*53JY*-w&kO1r{G=MqkgV-3}@Zqy|)v_*|jb
z4kKw2zOhD-v&vAJ6{ej#WUK4?>Bl at Hm6m51rVF5}nD1*51y=Md$F=b9DgR$fR~;8s
z_w?^BOLsS{2uO$0xir!(ptQ8KbS>SXpnwufcS%Y&qLhGicX#Kz&+qf at -*@ksGiPSL
zbEdAe^lNOqInHAb>ZCnE(}3o<n|^v!FFME?l#bt+OZj~QY&K>>ep%wPqZGcCcLfO?
z$b2yu93fJot)T~LQKQ!R0zqfbnR7Gg$7WGKE#4CfC0?CV;wZQ{5DnWXez6gEDEOmY
z7T8dPC1AeF2)eZyu!Bw8Ws8cSF+=c#E>H>D<~@{k;<DVhJkfeeNT&Cm?|6Jt^Z2B4
znb^zg^_AKKnyvFWAzb7*B4Py}zmuNovnJe*6z$m;{(11fA^?v|BXiG0?<229S}%Zb
z+Dgt4dchD14|P2ZB53&>{2z!40+$>TfShlY9Cp2SP}O)4eK-L$bzUHxNtry`?c9vO
z8}FG=B>2E9^Skb<Ey?qPUd3DgG_-9_X>VSN5HFHird+_J5QK#eH8ahLxlPXyiRNPg
z7qL;5v$Pj^<7qYFq8vwxyhGh!iSemmwd)J!|6w8v=v|vIqf$O6fE;%L2Wsfaz=K0B
zoIv0CaSzH8wA>|2n9j at pl0$y>;MtDSQI?9wr;olrbcO0JF}1)Yxo}E0EDE}p`>>KK
zxX2gc<@hZ!l;qjpJ<5HdI4bNO#!8iH$yVWaLGDR!F>Ufb`J;mkQx59PeB4tj8Q at Ty
z757<;Ifrv!{~nj%=lK3)_tx~#Twr*G)dTv+&Hi1g5#csjGo<F78ZJ=@79r#~{5{rk
z=@??l at ihm0EGU}YZbHNK7V9Co#@q8Be+pU^fnrBZlTr)PDMP_QRLG28J{B+#KrkXi
zV4o3^GcvwjXq#EyR6<GH5 at P(D-`yxtWiiJBLf>l*V<i$w;d_5Z)~}MurRuLk)vHlj
z)zI_u*}w(SPV_xpsOzIzATVAIS94=fDudrr8c(3ldzcOm*rARsDUHhZ{SyER!eUi)
z1FNuVd_lRe$~yQi5Tb2*bD|K$WrTy&Kgyy_)T(zxAq=`$>B;Hv_c`qS;rVI1BqY6%
z6`o|mj at V~j-7?1{!jbjT9l4|<72IypO5xcb6QvlJUN#D~J|jSRj{0&MLj$XF9K>RK
z`Y3-XiDKGOO2j_ez>IcRA_>Ki3GJ4NY>0biiBm(y*)giD9{fu?G99Edd5y}wiHhvP
zY at AY<KNw)nc0}$p)f*(8WWj>!5H at y)uMA79pL>aQ>_3evqRBS7g8`R<7yp@$CfbeP
zxo;H*!BkFuMm3RigacswT3RsF&cW+>+`cs$LK?Te1mr;lO&~Lrarj`+4qAydqw&Aj
zT+WF9;AS~kd;UW##TG^~a2)s}!poKDMD~puiCzoP`IE-rP*Y<mL{RMg at 8C=Z%ujmQ
zh}xW<`P0)b!x=Lz$cC%;fIcEwI$5gA4&U_RMD!a+q6c;DI0%ZPHm3OeE(}yOq+D)?
z%o0hn<08?kRzwCFmzD3L4A<l6k6nw01XW!>l1KyIUzLnuB&^1;C3x^ltY4iqIKL>N
z>s%nJ at Z$(k1RL)0L<a%nB^Cj{CY)im_#<ou$m1a@>cj~R3yRdL<-y=8%Y){`Yr|+l
zvpfus!$p2<|Gk%>o;l(Hq-lCzFrk<NoqDB_U=arbC7#=J`9WhLeC#aG*!gD|Li?~z
z5 at D8TOD4pejM$9a*a5?y0y4107!OOL;8R_3;mS?$cq<RQ5;+bJhv~3E#YC|P(2kQL
zdWb1L^}+Ouk=3uq#R%9-=n#t`Wawu$PDGn(@;GpzAR-2F>f?bxShB<CC*a7)wID0}
z;NJ(WL<2giaEx-D4s03ZU>5 at MI!qjJjG8ZD%T0}C+h92hfV^eCe;vyhtrDV9=8X(s
zg at S~wmvb~YsL(!>@QHmG17;mTQl?=~VOyKKBCqt}rPs5~XFptt&DkJ1Xosch<OLWv
zb(%afGLT?3>=h04;88FNG>;N{@z<j at uv-P7K<W+U*pPNa)WI3ZRd?zOQYJIMj2huD
zLE5EWymcDyvP;a%TV^7~Ch_+V6vBT#VMV7a1L~J2J_s`mCmReM`U3$Q3UKCD@{Lzq
zaF?c^me%o)u{Umh-zoJunXm*eSRUd!GH#Ym{BdqFcbZ{CKaruatPnWqbHq3hL$;p`
z(RD{OSYo>>Rh<V5l0K`IzKq&>&18v#3 at AsLBWsdm*Nl3IlOmfx(<EC`zWm2sneDlX
zevAyayb^IFSw at dn*wT~LkSGxYmH+DT3Pc$4j^dZ-;VBY6;+J8522&$Q%5U6O?%Fue
z1<a7iGB=2+T22*EDT|9IBg~<L5)!};`Qxe*8 at Co2b~Y+}Asfk&w8&|VXwufeShqD)
z!9TnpP%mMDDj|dNvAjH7-JT$Zz0Dx}SxT)>F!Vg_4OEifoGNUlCf4z%bHyPna(FpJ
zr}oa(yC<3`q-+bGl8Uut+{s at Em6io9JLE6lpujkQ*y%fzgCQva<V_pQ0BL$Ym*^Ul
z`!r<_v-$}9yW$c;xrkwbsxyl699|Nt|7L+|YQi$#n+}>|fM1f at gdJPqycRRH!N^+x
zV at gMyyeYi4lt+}`|B!}p9GQG0WsIJS5=mGXd>+}m(=Zi9wEGPsi$Tnk)rJ60gdb3h
zGYtgA?Ryf!TLt0C@?krd%P`K%i5*zr97T>$-`GZk`8KzD*e|W(cfzl}2QflZ2UrmF
z&vuZ6D8hJjNrS|O5?>X_N6Eyaor#U=VJ}wofPZPAYiPpw_aiJwLcd^9jHqMDHITkF
zCTGHOsdGZ8pj5mE>p6Ca2VVv$ZvZ5%*F9YZNZZ?v0y?0tbAarVtsrM8jDk at yw<s2B
zNsXJswpy;ep>9 at xSb)zojM^aZFzOG!FP5DF?JU at rw~7|F0MZ%f#T))Y2!$N`3$w@$
zVIwl?i!q#uhhwPT!E};MlAS{sNLid1NeDudaiT>aY~j)h*lN!aN4aPFA<u*qVs25s
zwDF?F?Z2Ub{iK5JSFcc^u*iXkOQ)Wh)3_ywqPeNvU=LvFz!3!Cp4^vW$X02ZXFJM1
z&U}k<d=jj=0KZ7AW!g;c3m9W15)N at aVG$8bbfb<aZ6<bLwh%a(I-(0VQOJ*ygCr+j
zq-+e8;U_qF`WilT=lL2&$0YRe at ZI`5(*pX`%ROZ5x)K*QL*Qj+g>X{E#4_Zpopo>%
zwh5d5arhc%C at oCJ*p=Z|8Kt~C1bGWdR<Qg@!<2c+B&u-=zExbKFkov&#iav4QtJ%b
zMB&FGGKdU3#b(q{5Dc3Rj=jkG+?2KK4>m#mu(TNn?pU0V;_7eo44#3vO$XSoI#qdr
zy28$$0kuU(gC<Czf1pBv{gg=@v!gQAMGf|#e!%_CBQeuoqb7!TmLRH>p$zy?6m1pj
z0E$VnpF at 0J;zlwvZ$zI6Ng;EklrqDvJbii6L{aF89 at roCsX()iQrB(ghq7>DkXob|
z6dDP<GF}uQ$&q~`#hP~04sQBtE``xpL==88rgJ7Z%(J$>1&Re_a-azOUiy`#0|9&^
z5L=y7e`Iu~=}Tk^QR(uh>klz&w}!gAp4<f#*?9uAd6;tnafw*o*Lb`Ay%W$d)b}pI
z9Dh1p(S{p)AdISn$Kt}AikhK>p#&49K#&L3GEsPFFEz#JJDuU1a+0q2>#$;i4i$y^
zxUNBRF?_KRLN7X-V(@4p9C<3dz}=5{Ad&$MHJTXF{WQvk&75nII^9OAK<~+DmHx4%
z6AW#HKy(c>fL}F8WA!YG0a--7{ku2kzbwNi>z`#<7;)%|U!nKF$D-#69?EJgeamUU
zJP7;XH+*9SRr3nU{G);1=?b)czr=$+2uNkCqlx&U;Tg67vDl%;fKn7?)0iwM?%q}w
z$Y<%`Agucu9*TvH at s<-J1+3%zSJQNaW7ga2lw#y3!fo|#nBZKzI8yqT4ubyq;RPeN
z>5mvbr948#SL?;GkkmtRC>#M{#DIy)KxG^dq|zF@=fJck{0~_f!}Yv at m>wUwOXH9X
zxV8(21E)ZaZIxy*NV)1dF{GmrHg~o{xQnEO(B^%+0N}0(e~tQ)WYq4N&TpqGxE}W3
zZ3^ZW%r4tO%Dj7=m4f>)QPRYuP)wn%9|lEloKZdpgz~*k%x6V53}$Ya3ZuWF_P8(x
z5uqU*3<wF at Ok^;_|MAG${e3uH;?Fd#f&Bc}^1MIwi?sJHX^1NH1p{vDvNzJ&6G#)>
zJ_Y((lUcm=n7mptv_J9>Z*t$Fo6lXKn{yP*tge=VgvdfcQaGS67=yVbfs&$zR}_(O
zWQ3SpG|2|PlXoP86deN*15*!Z&=e<LY8q$Z(9zSx^XfoU_n)x!QS0RGY1QPc^?}ir
zaYIC#QG>7lszzan+M9ozQ&&%qOXp9!&IdLM=iD%j{hpU_BPdT9=8J*j0!kQ^7i1~U
zEp}p=9*pn5ie5zLZ$EvbUJQ57=A>YCC%`wTF(}vX$LtJfrPGHkiI&yr?;SHdV~UI~
z{7&h^i+=$)I7&Z+)HDy=1 at wUHy&sE=iY7uY6SUD8ix`x at KD`x7 at LzT*JDVuTDJ~(r
z;8ru)AASw`A?ZPC0Q*8u at Y)^T!X%Vc?focMVcg#N*o)n=5z$U=yIUUXS%9JPv8Sy8
z89v at TjvQKvb{r3jhmq^U>$p&Y^nVJX{TmGS(;x4_gSBC%PQznao@$p<w(f6CN4=tK
z<{!^^ipcQkJu^2~B7`26{Uga^i;LVNA8i+q5rvoqO at Idn)zZG}r=bSjLqrA4$ZZF|
z9bU;!cfXk6vWb!qbS1;KJRWK~nAPfaTaVogR$v#1V4uDCR&lU>EAbKamWTO+ks at kv
zI2^$i_l=*YG$Pp4=IM1hTJk3gdV0#mIvz$BURD%TN^bP9rA9p4PK~Xqbe|E?v?X7B
z=!C9Z{!l%JJ_W2=6cZ>=mX={l#0(dhG1b5We=y8^h-qJ+N4Yu~RevP7o!@cTQ4w48
z)~Vwx^F9J&3yGM!d6CQoe at F1lU!4%9!rizgAdG4klp&6rMFn&NejB|VJ5~tB=*qrT
z`eLAwmiFtuef$M_GM?5p3aI0xFQJ9rh%$LB-FDNZSu5qfeL7<R2$!5Jqp%r!2ZO+^
z=<p(9VWtvW%f*$>8>h-GH=>d~Ge<XgI)h(AoFiob?eAty!y?pMD0(Xs*FMDY at gCxn
zmz_7hF|?Z~jPh1tI%wZ0+e%!XZ(08kZghY2!xhTMYK{);=L7vJc`~@GY}#|=YCHG@
zB)fOd>vWUkapfR-4<|@W4RK_P5i~Rnknc0GH|Cums!iMUal)iHkMFY{nCONSByI$Y
z>AiVkQiIP0s$xD!AdYSu1^j+(+R&1P&Bj;k$%rh|)Hj?D_kLRWg)#QCnptIW!EaQ-
z@{_TpJ80&RjD??w^n&=ND*f>VK){`TdwDe~=FDwud$~KKA;@~(K219Wyo5|=5+!g-
zCF#RdP^`|pfskpc`F8<P>?Yn{d#MjMhMsP-80>r}so!s7G0Htl7<D&#4~keBwJ`@7
zDWcp?lWu49-|7%Y;+3D<2-)mjYqRnSPrjUYc_$lRiN(%u{HS>rj=uPaapxj?^Wk5p
z&ugl at Z-8yJxu+f$j~R%Sv?$43qXeZV9`-6LVg|7A+8HPmdROkXf1=>MTo}NpGx{7u
zu>@VVFbu&k;YoX7H)NHHy&Yi)v%wC3_ROAk_%2&?8M9m3R#r%o@@srVWE15p(}=ul
zFLoZ#GsC#sr;DGj(w~m+TvUew{+X)q-)ElE#+dgWzC%k4toitwWgJHZ%45QTCNRoD
z))*qwcDto+uGw-|7!dku>145rDK$EH7%l5JtV3A60q+9tz}XQ_^6Up(gXH{tQjQix
z{{oFP=imF6JXx38Ny0(b?+&){iq@!u4efiJN}pJI(>z-<nwRbga#R5LZ=6r<9AMIB
zTD{gE`z8+fKFlw8&^TXmV0zojgvKXG$n9=??k;TW%0ILAI?hJ-o?Ci)d%r?FvfS?D
zt^80fHzj4oVT8lrfu<8X{Dl`;RW!=4F`S#O(4z2yDLXagj<21&AKOc1!Z+!x8S_D1
z^szrVA`WkBG~5I){i!p-;&OAp_*+3qcU%Z73X9&pniVkazLHIsSchtTCR~#a!bu8#
zWqdtP-sn at i%1Q6T?Q|=e1snR#Sxwe?MO*UH?2KC^yG~#bQZ{*Rq_A{V4c*=@@AgTk
ziC+wH!`nmM!{n6CSJ>-#`v7(SAkfh{eA~erRkb~e@<5*b)9X_|viG3H#>$=6gE^M6
z5|kosS}mFen&-fU!xr|M`V>?p?K$g at WZV~LkDc-MXpmEn&ITp!r54WwAK6L^GdF%d
zottR7#FAsmNf}Z4wdYR{3pdr{c1}@{5b49OHIxZ3Ipw+E3cu6}3s6~Vh!CD&x&1SW
zrjsiS-?^@=z^Q0>%e5kY^|YXl*m^}(nbyBu=|S=oP1?K$f~upA-O1ZWa&!pyb0BNa
zxbjd0B7KFnY at BFZcVYtjWR852uO36Pa++N_u-k8!c!wB-(mj`T^=acBq-Cr8>7yOo
z<Mgn&5mCe3bW9TS6v-N<D!*Hw?@FHZYHXxfuyudVxJg`5bJlp&{gB(P|7V}pY2|N1
zAc=k0E7n^Dv_t?FAGn8<Nk24%mI#8MDxA>lNZhe#BBFn^(lee~U1BI^YuI(<;p(I<
z>xnT-Ldg8AT{5I(^@e*3Q6eqMjfWqFQQr^=BUP{`MG&JLuW&MeAUSL7Oo_!$>+z|K
zU4;$cu?5LbE*B=cRt)#qUh4|&S-lIMyl=w2buCKlQopbuZGk-z;6Vnl;MFiE9C=G!
za!Lr4xvelZVmmZ%Nj|;U&k*f?46E^5-U|G><i8?!E9uXWhr$q9m)e9k9#CxoU3IC)
z{|=81!ek-*$oA_6)O0H7=sW#=Y9`IdQ)#jY<8S($c8i;9QSa;KHri6sLe;q9Ju{dc
z;;DBhrd2N*-i#Ied4Xs&%|<aJIxq(HY~%CBBHh`>%NEHjZPs4mtVf&(hep=pMU%&^
z2`4{z-b at Te#nE4P{&_Nju2}dPNY-b|rTWULcg;_T*J^Fg)hr=<xna$xD&&(iPqfAA
zv)S#c;dH}5)uCL;>jjR(<_K-JJjtlrt*NgGq#7}#zMKFo6RoIaiB>msJo1=>nlO_)
zWsm`b?@V~syX{^yu;Z^!_jfvf>V&7#z*z5b6vc*_VAxdH#<ve&^kkhSYM;U<x*~EA
z%21Gy&OA0o{LutwPQdM~=A-Y#l{Qv#pLK|&HGLpD`O|L&O?TqkM}v!Y*(dW#Y=A<p
zu9j7Z5RdW_@>QA4*O%j~^5#ypK6DRv<i1^Ub9p&YLE_lK?>HqO=(hW)+p`n|X{ocx
zRZxMJKZuM$5cG0)?`VG&@8EV8)94!#M59YF_e&;6xjjkv$#Rp49Vbb4J^FjrsBgm=
z(GZ?2K+3ksKK~!!RPywlT;uTjp6^1mLMB}3fZ`w`ZD_j1E3NYWBx~&Qt6<C7f#15x
zJ<UbLQiNBtIL~TQc*luMhH<X~7_E1mCGxjTfFXY7uh9JOK}y!Np%@>m*zcHz-5z}<
ze!p!yd!R6?F6z1ui7IcOcw`?o*}wP%-Zur=f*lhHN6<q5+vwG$e$O`;1+}sB`94$T
z?Kt;}Y~!9P{@FqMeaxW5^`SEtO;<L-e}~MqZ8_2aC5R99sw2G-Q at gRebNMoabd{dI
zOcKJo{*LbsO3+`gCs?Rum}ldtj^i+}hCPz|@|XM6wVl|!;tGaGLi;p&)5YVq8G;jD
zbSIuD9{wd(KS^=;Ba<Nh`vHG`<R<V+*>5xDk&`>%wx%f8W4rKsLD$9Mbf6>&ldOEJ
zr&M<CnKktTeEFZyR7##OMNpRx+SCjn at rTLjAw_azr$Hk4K>W<xRJh;u$-LJX^;OpG
z1hSFZF1TYj*_0(Gu0PT(a46To^8gL~O{Hd*#89!D_0Om7Be~(s%~N6%`3hsX9cME|
z>h5*5smT>xy?$*1bd>P^%Qh3{o${{r4#W{CwTUXH-D at RV{T?{FsXpqb?k>x8X)?g^
zB+`D&vI4LkxG$T`fc{jN06k#l{bFkPxo_Z9fRyiAVqw5l4NcnvXUob;gx5ZCV4T}g
zK=Q~_#M7_c at j!Ssrm(uDvp_tsCD%-Hum&1I-uKc9+D~(Jq%C)iyMJ<*pEyJa^@k<2
zWGMvRDro*;GPYOK<<~_D@$;FZ)$?BC1e|3G;z%fuR`)=~8l&7oI_r9 at RN30`Ph}c+
zT3=6-^?7m6ljDfCIQy9J5N<!rGVEE%7s{PeRfArZbL-bqkHYyA)ox1#FC+0~6l>6r
zwldnU at qca|I7vgk&7{A&@FRfHo<6<2c(Z>o2zVemQ!yi9<234|pF0$Fvtuc9><al6
zkXACQ-8oHA?2&8OxUr-EY2d|8YeGQc*5gpS^}{+-Y+Y(WpT|PSO~1k8<?|oJ46E#}
z?pcfmj=txMpBwI5vzFtIe61<?#-f|ue?8Pu9^Gqye2Q-UcE~(VbXjVXOV331*m7mY
z%2Iq^&v{@a(>zmUP}yw+Ki99EDGQ;}XfPh1%Y2BSU#}3982ou=t#8!aNgl8<<#qWc
zFyryhh^8&=?NxVK+wXb5{o6V4ibpZ4y1ELfYhWRN!efp4>9zX3`v(#<-hb(W9G5mZ
z`)S2{QViut6M+gCqha8%cOx;^eMR0B9OT8s0+ODq|M(sEKx7+K)SF&|FZrw0Dd71R
z_m=CP6z|pX_CMoKH|?D at +!{kx-I&P!^lY3 at qA8b3{(gI54Nv<CXVWhNiFBvTC<kl~
zOH%faGR(=CMpX1rSOASOpkoRE5mMHJBivVTAWbwFMA-V3-CMI?+Z?KgJ6l%T`svrY
zde1&8*iWW#pY=XnycN4M3Bb+t=jFqwZF+443n$#Pbs3xBH at 08A9GCnp8gNUT+KO77
zY_l8QymiNs@<-z#0a^Y2*oy`DWk3`4!j0yM_U|OBg0{B at cBV@I0a!*V<W2Rx9<-Cb
z!>wly^S)0HIt<ISZ!!aexF1HI{?wV=;R>i5NqeWQ-_7xFvR+Kd=We;t-De-IiA!F+
zD(dySPS<rVFmMfU3TzD2$O)_l151n;NJp;%_X^3y`j3P-vps05XEZps^_De;yv<jR
zhk^ZXh3ncA$fVeZ{^l$Dois at Fe=&K&#mj07_1!Vl!2KQVk()K(JD4^ucHX_z-|&#z
z9%sxIaTp9WW#i(yoG}UI-7H!E-=@}JiR!4Eu*7MY5_b3mG#J)kj9-QrnhqY1ZeBbQ
zIP^IV*e%*H`A1q>zg8M}{^H%;(9&8Ow_nsHwuy8dEt~N{n1+y!wfb2_)*a>INff>8
z>V9AoEn~-zG&dJ-pJ|h#-P_b{YY-eM8f|I>8a!ao(L)DXfn1l)bNxy^lvj$&qxGDV
zhF`DRgCghyU#N<0Q%-x^?9dvw4sS at _5UD?2ZZ+PrKcNV)lTbZ``+DD#OALH(yRz7B
z!jtQK$0y4=%yId%N{m!iP5Xo!4;%Lhg#=*H1D2_kk!hTcWZY?eYQ>A7?6*}jRZ*}i
zgK{u&B+%(P{G9#{qwt&6wS?Vi>%(8d_NTePjuoeXuYyn0_{RmF?H1>31D@$6(Y{};
zr%etu`{&z#=e0+lk+TEGLjX*VJki#WV57%XAh8LO`_&8$a^MrE6D}CA-<`fVM@@QL
zZ;Igg(&z5qsKl6LmOYqNIunfkwJ?n{Wo^;~DNSmLx}IbBzGWDN^&z4+A6mz#EICEq
z^3zoizd&77?00AGU8tB6dq^8`UGk+{n-4qdw|atAO`@*+Wu+)S5p^T(^LJvtFiLON
z2f>{PAo8)$Ig$w;ky3skud<dx+IznE?-D70lIr&OO>XA5H0iy#w}!Js`yfPTjrq2{
zFH0W270)_V|EI0O@`zW~XG)q(@&vj*9}7B?6rT9jQ6L1@`}CUrQxU at ACeCLZthN{`
z^5MyJ+ihGa0WqY2*9K+Kd;2ciG!~GQPbQYLPmXl$ALQNp#nXt>*)Pw)*oT=95HLem
zpF#Q+pRSz6ATOGRT-7tTN7wyaB*k-`Xj)2DF_<>uWy>YB5kk;i%;?Z>9Y^;PPInbY
zh|Kx>y_VdI_}>vBh1#D!D}7(nY?pmR66?rK4L`6uVZqN at Uni<Wje_(pe=N%rH$1y1
zHrZ at zXrUx6yieBBF&w{jwlLkDj4u1xv-lPOsNVhejQ|RRiT{!A9t6WM3eNj0`Q=uz
zQndl4<!XgW)9+p2rtt8*8-Af$*d+qYR^AQ!oQGm2jJ!~Dg|#D>R+BYE{7{zN at g^<y
zBVH<q%o<M2|I at Q5EKo}NhFg5(bjS&32gOu_g0up~S2J~Rq}RJFP<XEwIdK7KEUyER
z&Hyl4lkvQ{(7!udldE?U>FfzkPGS$Fhu+H)-)=Yn_~eA)xNpLh<MlUS)>p(ulrJ=z
zlpS!+fk7X at embYBYdyAkLK$pFl_p!xt*iIuWU at gR?(oIt42Q0`gP1?$q9>P4gn8fT
zo@*wtb~f3D*SxQpiS-f4O;aEoDag(oY7E%9`KubFL`e`f=VFg&cqrO7K_HNaK at 0&C
z*@H2GSl(`fAILvM#V@@Fs(zk}l`m-d=1SRz5eE)-ju)Sa+WgBwK0bwy5sMY#qS9DW
za^TRleeOPvv-PJgVlRaozgvci_J|yQW}$GkI8MIBjZ{L}Tq#A=WGZ>jgdmvD#7a^B
ziuQ=vzps;11zpb~*A-+SN3`X8-FK)MNInT=UjX&mKFkZ`k%aAb-<<oo!SG`HdAnY_
zy4hj!o}8Q{TAU7AZUQo%|J0i?2=)~Vhd-zXtfdOg;H<Q-)q3Z9N|_uLp`0vDybC;6
zxT4#ezjR!#$j$rj6of#giSl8u7T`3H5{d`i_vjCu&syi=Q6r=gG;b+fC;Qg2U090#
zhhS<}Y>C`x#VUdwvH%4Id@|Cl4B0 at T64Zq_Ha@nfNbvNa;N{XoVh<*INNq=MUEext
zXAflcPQQQicU{n!eZExC$T&b)RwKk(-hq^zLl!cgA`GTNr*A=+sU^~&gB3!qMG`&{
z5^(t+0M^-O*mV6Z&zMh)`@eTaNe6!tfJX(>y_T#R1`s9ow;?hg<{bBcqAJ;BVb3ED
zE^5-R1Fuibk%*KIlSkByue~0gTX%<-NZ)1-`6LC4&)U43AX41S$W2HJ`5_~S&_^Q5
zi&`=sD&lw?sCZ=w7H3tP3jyt0T=Jj~WE;J{0`=X6BCx+`|8W&E1!8___FC1;6wHdt
zgEr3hq3w1Rb`&>;v3y#yvT9o{*OEN{pV1NJ#2qzsdVzAL00G&G3QUHRK;ub7Ph<pP
z+4@)Ci>UbOk#0AVLX{(Wte_}Nollqe<sFS;dF<UQU+g3GR+xj}#PxPCtl0`&t at kse
zx&PbF1RvBIloZ0i>;d{Hc4k=;eYndn#%ek0Ldc?wQsz9`fC415!I0bW#K8WA9zsOH
zD3A#6FcR&ERv<J0Ok4ZC>G{xm+;WXH$w2=pp7woKwQ)xg1%&~empT1`Xyo>o#h4uH
zDUKAA7=B_;>!7E&4_UW`y+;2}K%#76%v3MG;iP{=9jhAM{LMdl!eQ|7!<O`7g4VSv
zbv>#w)qf601}a83XJ_#mbx1V6Z)2BKGR_+oCZYGE7^B8skJ|{LfdA<Gd{*cP3s80j
zf>XgZ<tN{9CvPx-w?0R`YnU9%rv7{wp(<11G5;y}*ci}99c=X(4ad5-PTohkeFmqJ
zd;&q7N;B^$Q1(H+fWUSC4mp<+Sk4QU*2DgF0UonGc|69zP?nOVTdv85y2Mj|cQ*r&
z%$~;-*uO1A$+DGV;f1S6tH at TNN1W6R6o<efi7{>A7<>N+jWW?l{->CsQ$UyK+YQrv
z9zqN)D!_D(PLo)P8<LL at qHJ`WDr*|5qSny=kJT?)@Oa=- at 4>97qiL>*T5O~Kl3&qY
z?1Gx~an2`QYmIR$Ipa-`Y at zLf$U_P2K{7rFl11bU0V=usb_ at s`2TBwIwStCr^l|}%
z0}K2AWy}?-_(?L0P$P695a|rig}Y?&P?DSmpgPv9<X`;d;gMy<AVc!zhjx&rJ&!W#
zsK`F94edzG-KX=0_i6{}3Iu$|s~7CG_4H%#)$9Mn?A)g#9yOZ}BbfpoYX`(81Q%UX
z<&Qe_kH6v0W&D6w@)?T+`M$0oKwdb|9A%}U$gKzZ at qrNovQ8Dm0DY#aPy24`w-xCj
zdUCMof16H6eZK=&L+ylM%^lNbCWr<pQs7|>XEFn=$N$(<46YvP$u#OANF)^ciDOE#
zan`W&Q%lg at IB3OHqlt08{Eb-PnqA8?Av!!Z=zlVUS&m*5^+Er!+F{7_3SmM+BukKt
z at utFLqfdl}lJ$R&&|3Y?>aIon{TtQLVs`E4Q-_tMKHsVT=T%D9)~yw7bSNq$dO^PQ
zcjfY)+vR%lc#Bd0-(|B71z7TjVpss#hii at N##+vimTTQX at hcardf3OW9`g+4UioQi
z)m=dJ#;~Np#t>6mEoMrntV3>FG>$3F0O at PSclkOn*1Uz|^ZZI at 2Xx}b1sdp+Cn=g1
zfDn3;?N^tL7q(5s*2pD+I-tg%K4E5!QbHTs){4n9H-7ID*mFv#lKTV>vL;j~I(4oU
zpbmo3m{7f1h3~nP at pcNK2!wD=!fEk=;5ImjMK+Gsgpm_Fuf`k%A;D^&IUbBjIVL|`
z88m<G!1j)f=kPXd;>2$4kIRG+U*NTV<_{HPcDY}9K!^Q;&hO?IpCpCbuIRSj0VrEA
z`^~Kp)D4sS<>{ittr!fVh_KIE$H%PzN+Sfk@(n{>@`=V;J!@t4(Ln9r5RYpMahXR3
z9XaJc&eJ0WFmYYEdMq<t&63QmkqWA|TOzBe2C!T=gt3}h8M&O%ElO_v)a~|<Z_w(M
zteC_<)CBbLPp`tKWOrOh*Lyi#;`D<~GO4F3s|_m~oj1kE$$U|?Q$@~?4^Dq^zpos!
z9IijYA0b6Cm9n#bIq_;@-D;JKhXsmUfj<qb$kxU5o1S*bfLb5!HsNW4(8Jop+?D(w
z^&fXDP}pYz#QuS6`@9mUKciz7_RW6XGHLAD*!b+Lo?%v8$_c@!UEOXeydtBXiTaXQ
z;6)#_%Y5TYVTrM&^7&WP-|$%qE8QUmi4vAj>3YI6EusNRZ8H?4i>D1u)P7vQPCFB|
zcUg41%#4Xl at gn>1?)>|0cO)&;Ml+JAc1))aI_&rYO}hbbR)`R*G06Rn#<bk}ryd_g
zp9MllzZ9NjeaFv8_hO)}9tQ%Q=Z_99V2PV#j^&}2F&fby-rOG{<FJ0U=`Q0?0>WS^
z9Ki-!CUXL#9VPw-9-T~@pD9dfF8Bwf at kWxj@XUj!wH_%Bm}CPKg)c(C^(#2w_`jpg
zoMei<sxrpMEAL%9f#SUoh)xuNh)z5Y&h6j&QOZ{JfSC*qlgj at 48=(`X$KO`IgO4lt
zG0u_dYYnRPrCN2v^xB|bwW?IXMeu)+D?6K|5D<kbNuIHIAzpD*ZKQA{ZhiPOGFo#f
zrazxMTPs0#8Y^^%W7iQoOhkD-Zp at 2m`n&F_MUTV5vsO{8;rJ25_^xt1LM%J5s6n*`
ztP0lXnr`}<HKd>`6}8T!YS%D69?#|*<<`hjFSS}$?|VrTP!Q7aXO62EJ=KmmmG at qX
z`%nG75I36BTJrrg`ynuls}3D=m^%qf!+_A;41OzL<=^&&sQq<%!5Ebj*|}p}N<d*Z
zJDUbovQ(~xPNnpFh5i=t2b$`RsBYzi!u~rthV&?X8Zzs*KJJRz8J5{<W^=gQVox-a
z26SScgxcxtNNCzVpIcAwyz$rDr>1Fl*lCInsOcQBP8V at wcC+kM0&w#Ay)Yjmns#3E
zWSx4DNN+>0-^x1CW|+tpxpzO_JH|KJ3$=G{W0l*-POxZaKaW$`8BljFr3CTkk+&Z0
zED&ah!t$0L+4BnzxN{+!7ZP6m$oW<sj~|9_S|7?84MD+34k-1g-};5fzKMNg9XV=_
zZ*$mbj`yg^_WXLgYM^4N_+5Mvdot`-`I_^n$G&I(t+V`qQS at Vj^RN;tn<biM_IlNy
z&H4HiNpqUhml>HBmBffK+%FZy=jp0XL~66h*-8)5l!aZ#T1#uqcm}^ueg+{=TP?b~
zP;zj7rw~P=nIW**xJE)G$Kh>BK|xwp?>^_>8AB5#T9qay3MWXYV%eyYg$@Pz<O#pU
zRPuMNM`lr27vrBd{qT*q{1wz~Y7U!1!f|`t32pVicgcj|n{HrK3?#tN^s6&*(+_`a
z9uTTLqig9exXi2zI&9z^_WfFTC2W$hR^{|_vLfC;LCOBo`Yb!4a;>qF`5mra1I1Qr
z+TA~;zo}TX2ElnNbopqSpWZBz$WPhipR9(z&(n%2cl(Z2O9|8o`Gep|GG{e$B568T
z+C3=~TM6-5SOFz3IWEcgkVL0WyI}~<UMz3VMHbn_-h6!!-JIolrOPoqkZ2dVL`LN_
zcl0sGKz|3d&HxYgZ*XgH*9VG$3c&(eO5!E+uVEB(afE at +ep^*8-$o3nizI{pM)$Tb
zPmJV3i^f=Tg*|uq?#`IFY2Ixh?5mf$6w}%6W7uT<=`)s;Q+X55 at 9Q6p#V4KWiDT^g
zS|lR=uBa<ecK_Uvh#Q-K?A<W0^aUCXdaiiK)Jtz=d`Aq^-Om^0?5Iz#gf-7!;r11M
zq|php6-L<F(KR{?DmeVP_y<D&j$7U^mv&pp{s%3Wq)vcuR>PK<X5ogf at 0AJ>BdjsQ
zaWk*`mNZyn2leb$>`P|Yi0#l!uf$z}ME$xB5>yY|?guIYT>VnE{pZWof3_ZQmV0%W
zwIJ%SdYgs*mN10Tj!)N8Bu#pg`ktZwY1*70`>`uP<2YI7ps;0O6v##>Ce)@8mGiQ5
z$KE1`3uc4jL!Z9X>taj~8j5N!A3o~+JG<w#V>@U|c41Ik0)**)dsVPfR^0Hs(?I0E
z^&JXt#|4bPEi_E7mgAE82S3+cEuN at ns5DP=o)E*1yR8a)5v-Lt8Z<XNj;Zk`{FT)}
zu~oSH*Wt_B$sg5UjcJDa8S?aWZ0szGND!(*cnm}_erCo?1F4syM^3)$<b(p3Xp?n=
zrPzZd+AR5m`Nzi7<odf<q}+^qI|ZiysahrDzm(YBLVhE{PQw^4`aX}Ew1;6)!wp;6
zA|{R7An~3UakFZ<Fs4+JQdA8(8kS1=x6ax>xu0=d4DN;(I8LX)HkjnK>E9+6)2&zt
zb``RBEu!;-UYCGZEDi;>Cc(9rz>)9Qn&zSlu>zFfJ at G=Hk=2RxCflyGkLAx6UvnUR
zQe=43OPgE%PG`_<a_manf2qdhs~Qb|rifavLyAlH(-o^BrVXjUZE~a6y^Q$;epZ%z
zofKGwsgFR4wH&Sgud&p#Mchvd*5}4AeU5(2gw7cqE4RPh6R^pju|Jfy4LOT%^DOG-
zFI4GWJ-6MRi7lxp-lfvk?M^$tk5ocBYL$wgMy$X1Ng9l(Ci$WdoA-h;4Z)V=Op3Ah
ztEiP-AKKIwf-ta at ypvgy-CUCOOy5Xwd#f8;`d-b|=O%E9a!dG1T5uJQ;ddXlCHZ~2
z5_oF+VyY6NNvg&!P>TCwRzq~ewav7;q5p$KVcLl8xA2mZ`Zu3r&d33;d~E+*yMW1>
zhDr0euewWajN(duG+mf)z21JNYsbT4qC2T>EaW!~yYbT^)L?YHP-Fwe+qmBT98*)(
z$HMt5k;k|r%I24Ts;-tf>&yD(coBc6qtq5FPUl<5KeV5IUzCty7klHH at L#6=XI`4Z
zEq!i#eDE`-t at bmO0n9HxtusE3Z5dk(L+UlR==Iidxu=dSO1MrD%*OjW_WT^X+lo(L
z at YE{n at Os-->h0fTmW};0dENa|lYlP+LcfcVWWzmIEHMxbudEjiQe7H1YExS97~I6R
zia{On8#YI-I3&HEaNb^FpFF9f>&|gY&cgy6bAsR&dp~DBt4+C2*ISO))BMb=I~g>J
zT%?N+f-^uql3JgQ)7#DaBrGT5|5PC3$@yh)!sBqN$_2!H7OL(?{9b!K6%-{WDQON=
z&K^-Zx8@&k9 at J6ml;YOhq~Dkm(gajvBnJxQ+EIO*!O_+YIm4IhSiMKOFqm6!2u|<T
z at BJkQw>`gqb#LAT5~iw1%(8LVUC#G2yVX%7L<kpEFkX4fnxb>(;-wAP4J7Ur{<WYi
zdF<vh*F*987qFvQI2tudTfQU6d3g)cwMJ<*8AOk8vU;_9UT<43*Y1V-x{xV9YMdPS
zZ>PDB5^vUD54X>ZItqM<j~6N;&B-PcO30QzX*s{X7ECQ_pRG=OrE+J91FgI$)*R;U
zXDGxGMU&CuDcg(BX+JIzd4Nvk^Y7K?w|c-ug`|b)$>N!ZGill~hl=*TmDnPS9kBxX
zLZbseJ`&w16CRVIhO~?=T|F${@8yyTCM&SVk)^T^NrW3?&N`^O6k;`ht}3j2$wPtp
z9#_QQ<a<(rWqZwOPRa_-_3PA_H at ucJUL(7G&mQv0M~5~4 at z<0TM0xwu7W*&oJsaz9
za5u^=Wh+9p)|6yLK?Y`k<KM!8i at Px);sPb7WpCKyXZe5Fgi|aacxR!D+V<`$+Uki?
zmFll)t`=@jc+j0|B;Th+`bX0rZT|Tq74P&b>Yo~#>z;Y$a!Zv#LzzhvSiwH_ih~S$
zcVlt#@1BoWCLJ@`RV{D#oX*Bn{*(!@TtE8cS1&0XNV9P;`_-ehz>Umks6mY=#`TNd
zzGw)kLZzeYo at 0tAu7!Vq^&@wSiqEmC>>lHyB at qE@XK(hihP4Q-6XytW>FC<U(YJp#
zZNg~EM*T<p1aghJia&RcSn>TmQT2PPtLxQX()E1g<kc2>yz1STUξ;zMFfpH|=5
z+%Orn4WY$YlaacjnsH`M`fm1BIoUZo(<<D#|2A8g at 7?(RC|JCoy*8Qs=~yyY6Tv7{
zt34W1sE#6S_xVq0hjWvvvZr&TgXnyd+ at yUhY@Bc6O!(iU?QX%MNZ{aBQuiC(u!<6m
z`O=cnG3A;E?+J94c;xyXn-vnJpmhb|5Bm?E!&+}6cvtXibi4SM-1Ja+<HmJW5BLRJ
zEaOJ4)yj;emVZ02z!)erb(H?H$T4YTcL(9iIa{54^!gBeY3J*%PzW|&s`=@n=(z at X
zuJPpYg5~Wub>->;eTpUu6^y1($}4kf_Vh=UWyDzf>1ia$t_xmtAVbzbqkl2X17RV8
z4qdds#}jUxcfQQT4uM?Zie(%L9pEZE=(Badvllt}a9qpKIS|Pyd@<CSOhy?VS&OA0
zQ8za6sqc-F1q3Hr$ODeTk*Vh`z;NEJ+JW<6PPZhi-fU}N5)k!xN{WM}9ieUH{?RIl
z!Rw=Ql6d8KIue~N(4r;Tb}jL;#vfL%k**pR15Vqggk?Ih8xp(`<mYN^zhNa39Q3*}
zW`@~pQrP7S#YIgB%Nt1NxzB87^vGqubAEO3xZ#E}_lqw5Ep- at Kn4Sw4RK)LAf|{lk
zrZJCCvV?7hI<4Fyxm-0FM%5oDGrvN0E1`El{jF8|S#Y6PYen(e+azIMFepjXH*?DR
z;ZA2 at r1bWtwf%pFC4<B?C$)6!N7SSYzKC!~9QPxt!q&(S&qt0sa_-SVYp-%4A~Vjf
zSPD#|EHbzgHnn;a+iS(J`#q$^nftQBd!3j5PG@!>dzh9c)45auQb?i~azVGZX6H1u
zBEac5Zr<8|K{i!?T^~{3%_8?NR3KvpJFKa5=LMdzrIYqY<bknUNK4S)UHV9$3@|em
z_KNGKw*eim0niuW_DPZZAZt$c27M?)?VHN8u^4WbhZ$u)U*ADw9(JM^dyvd6UF##m
zhhtuAkL=%>uIGwNGCK5Gf4?4d1s2t_uPPqZCoKboB*tL|KAkl?KKli|6;q9><k6|$
z at s2oz@P~ukQAo3NNv#CB_YZJC`J^_MvXz_*pag5a&(b+m<yg;e2_V at 2WfQOqEt0;#
z2GWK4vbH_%L-<`*@+$1-KL|ty<Ym(t>FO9o9QZU{kP2|O_0&oFf at 2FLYSe4m)mt0#
z3^<CmYGC<wm|CVENI(3`i``<v856>!0xf!%oe51@%+VpCq at uflGhlp0kh+RXjl#+o
zqq-?xE44&^WOJ^>*EsSI&5Vkq#L$BF3fK33b<M^1TP+H$zV+oY9*W82{oH`Fs}@im
zF(gL%+?=)<6fzw69 at Tw()N_G{Yu`M3R5)T@$lUD$js2*bA^v*h$M8oik%VZr(qR0#
z5Cf8b28KjxzV@{h8fR9{efQ<ROAdtPrbN>X)s0hFTB4e-gfm9oxFl?xr)jg->56C}
z%Re$?0mV1IpKZ%ec$JuMD$U+Vx;+-`1vA5z&_NpZ5tC*Ts;QIFOwFXuH4`DP*C)L5
z#fUpbXYQW&XSGO1PY(R8lebnA&pBj0NYmL>kPMj(CQ2&rCoErDx$eD*Ss*lmlMKXS
z;LZs at CKC(R%<xbrLZtn4K*Jy?Z39IGXdx8T@!rKoI^XT$d&_4D_v=sHYGgJl62_vI
zSl-+ctyT(;nE at 4kov$6A{nkuxou&l=DA<a3cf}$`x-xv at O1Pv)d^E|7?c=*uvMZ`v
zG>inla at yMmi1PH(q&02>(#E$m1xcs+c3{rCEyo3M!hIwvIeUV(193TbTpGX6ZoaRd
z_nyS~s|JdmM8k;r5y^8~Kb8h=#=)8;p#9j#oyd)HJAl|)yP4tmy_eN(bvo(%zJFc!
z3KL3eaZLivEm^!#dfT);I`ER<7p>4=<ma?f*6Uy3wPOR}m68vI>NH$OpVYBKcJ*rg
zN|Gd1Ulf!#4ov-W+S_<VSR&+KJ%tT)ILa*>DZuV!nf(ygCvKnp1AO$?t<?C09P!YI
zVbC{J-}DwPWL-JvYiCejdhaHQK1?a5M3edsfjhVqGK^6^t8fang9jOB at e51MtU)}U
zC4Mw|mNyqR_yJlDZ%oz>Dk?d-$3Mm7lKUE=bd*y_J)W>??B5D;UuF5m>@*q;Ke#TY
ir0fj#uEZ>G-94>1-CMBLH+2BW-)lKF*$QdX;Qs^4KT}5l

literal 0
HcmV?d00001

-- 
1.7.10.2




More information about the wine-patches mailing list