xjig-2.4.orig/ 40755 1750 1750 0 6175520320 11323 5ustar davedavexjig-2.4.orig/README100644 1750 1750 3103 6175477034 12312 0ustar davedave _ _ _ __ (_|_)___ _ | |/_/ / / / __ `/ _> < / / / /_/ / /_/|_|_/ /_/\__, / V2.4 /___/ /____/ the jigsaw puzzle available at ftp.x.org and mirrors as: /contrib/games/xjig-2.4.tgz Description: XJig is a puzzle, that tries to replicate a jigsaw puzzle on the screen as close as possible. Gif-images can be loaded and sliced into pieces and as in every jigsaw puzzle, the goal is to set the parts together again. Special effects: - Tiles are freely rotatable with intuitive pointer movement. - Tiles can even be flipped to their back (to mirror them). - Tiles can be shown as shaped windows on the desktop. Restrictions: - The game needs a C++ - compiler (tested with gcc-2.7.0 and HP's CC) - The game works only on color monitors. - For the texture-mapping routines, you might a bit of machine power to make them look good (it runs very smooth on my Pentium 90). Have fun. comments to: __ __ __ __ __ __ _ / / / /__ / /___ ___ __ __/ /_ / / / /___ ___ ____ (_)___ _ / /_/ / _ \/ / __ `__ \/ / / / __/ / /_/ / __ \/ _ \/ __ \/ / __ `/ / __ / __/ / / / / / / /_/ / /_ / __ / /_/ / __/ / / / / /_/ / _ /_/ /_/\___/_/_/ /_/ /_/\__,_/\__/ /_/ /_/\____/\___/_/ /_/_/\__, / /__________________________________e-mail: Helmut.Hoenig@hub.de______/ xjig-2.4.orig/xjig.man100644 1750 1750 16110 6175502363 13104 0ustar davedave.TH xjig 1 "July-23-1996" "X Version 11" .SH NAME xjig \- the jigsaw puzzle .SH SYNOPSIS .B xjig .SH DESCRIPTION .I XJig is a puzzle, that tries to replicate a jigsaw puzzle on the screen as close as possible. As in every jigsaw puzzle, the goal is to set all the pieces together. If you like, you can watch the time that you spent for it. .PP Any image-file in gif-format can be used as the source for the puzzle, which is then randomly created regarding the sizes selected by the options. .PP The control should be as intuitive as possible in the way that you will usually pull the freely rotatable pieces at one edge, drag them to the desired destination and drop them so they will snap together easily when close to an neighboured tile. .SH SPECIAL EFFECTS Tiles are freely formed and rotatable with texture mapping routines to give the appearance of a real mess on the screen. Tiles snap together very easy if they are dropped somewhere close to another matching tile, when turned in the correct direction. Puzzles can be doubled sided so you might have to flip the tiles to the correct side to let them snap together. If the Xserver supports the Shape-Extension, the tiles can be opened directly on the desktop, which is a pretty showcase, but you need a very fast machine for really getting this playable. (Any ideas on how to add double buffering to the shaped-window approach of the jigsaw are warmly welcome!) .SH CONTROLS The usual way to move the pieces on the screen should be to drag the piece with the left mouse button to their destination by pulling them at on edge. The piece will automatically rotate like if you pull or push them with your fingertip on a table. In addition, the following movements are possible: .ta 19 .nf .in +2 click left: rotate 90 degrees left click right: rotate 90 degrees right click middle: flip tile to backside drag left: rotator drag (as mentionned above) +middle: pause rotator drag for a straight drag drag middle: straight drag +left: pause drag for a static rotation +click left: rotate 90 degrees left during drag +click right: rotate 90 degrees right during drag CTRL+click left: same as click middle .in -2 .fi .PP The right button has actually the same functionality as the middle button so that 2 button systems shouldn't have problems. Only the "drag middle+click right" move will not work in that mode, and the flipping has to be done with the help of the CTRL-key. .SH OPTIONS .SS "Tile Selection" .TP 12 .B -file \fIname\fP use the specified file as the source image for the puzzle .TP 12 .B -side \fIp\fP select the side of the image to be on top, if you don't like the mess with the double sided tiles. .SS "Size Selection" .B .TP 12 .B -w \fIx\fP Select number of tiles in horizontal direction. The Images are automatically rotated in portrait orientation before they are sliced. Therefore \fIx\fP usually should be smaller than \fIy\fP of the next option. .TP 12 .B -h \fIy\fP Select number of tiles in vertical direction respectively. .TP 12 .B -ts \fIn\fP Select average tile width. Instead of explicitly specifying the number of tiles by using the previous options -w and -h, the average tile width in pixels can be selected and the values for \fIx\fP and \fIy\fP above are computed according to to the selected size. .SS "Image Options" .TP 12 .B -ww \fIx\fP Select width of image in pixels. This can be used to scale the image before playing for the case that a very large image is the source. .TP 12 .B -wh \fIh\fP Select height of image in pixels. If only one of -ww and -wh, the aspect ratio is kept constant. .TP 12 .B -no_crop The image is usually automatically cropped, since many images are surrounded by frames or textual comments. The cropping stops at a reasonable amount of colors per line or row. If this is not desired of if you want to puzzle with painted images with few color, you should disable this feature. .TP 12 .B -no_flip Before tiling takes place, a landscape image is rotated to portrait mode, which effects successive options like -w or -ww. If this is not desired, you can switch this feature off. .SS "X-Window options" .TP 12 .B -display \fIname\fP Select the display to connect to. .TP 12 .B -shapes If the SHAPE-extension is supported by your display, you can use this option to let each puzzle tile appear in its own shaped window. The results might depend on the behaviour of the window-manager. The manager is actually advised by the override redirect attribute flag of the puzzle shapes not to do anything with them. But who knows ... .TP 12 .B -no_shm When the program was build with support of the MIT-SHM extension, it might crash when started to display on a remote machine or X-terminal. You can deselect the usage of the extension with this option. .SS "Miscellaneous" .TP 12 .B -no_anim Turns off animation of rotation and flipping, for the case the machine isn't fast enough to make it look nice. .SH ZOOMING & PANNING For not losing tiles at the window border and for getting more workspace, the game has some zooming and panning features to control the view on your desk. They are controlled via the keyboard with the following functionality: .ta 19 .nf .in +2 Cursor Keys: Pan View Page-Up or Add: Zoom in Page-Down or Sub: Zoom out Home: Reset to original size End: Set maximum zooming to view all tiles .in -2 .fi The image quality usually suffers from zooming, since gif-images are usually dithered to be viewed best in their original size. This also applies to the size options -ww and -wh. .SH "Color Allocation" The program was tested on PseudoColor- and TrueColor-displays. On PseudoColor-displays the program might run out of colors, since colors are very limited and it has to share its colors with other clients. It tries to share similar colors with other clients. But if too may color consuming clients are running, the image-quality will suffer. You should stop other clients in that case or you might quantize the image to a fewer number of colors with packages like ImageMagick, xv or netpbm. .SH "SEE ALSO" X(1), convert(1), xv(1), ppmquant(1) .SH COPYRIGHT Copyright 1996, Helmut Hoenig, Heiligenhaus .nf .TP 8 email (for any comments): Helmut.Hoenig@hub.de .TP 5 smail (for gifts): Helmut Hoenig Hopfenstrasse 8a 65520 Bad Camberg GERMANY .PP .ce 8 ******************************************************** By the way, I am collecting banknotes! If you want to join into my collection, get any bill of your country, sign it on the backside and send it to me so I will pin it on my world map. (Don't forget the exact location for the pin :-) But you can also just send me a picture postcard ... ******************************************************** .fi .PP Permission to use, copy, modify, and distribute this software for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies. .SS "other fancy things from the author" .ta 15 .nf xcol (1990) - color selector for editing text-files flying (94/95) - pool billard simulation xdefmap (1995) - enhanced tool for setting up standard colormaps xmemory (95/96) - memory with simultaneous multiplayer action available at ftp.x.org and its mirrors .fi xjig-2.4.orig/vec2.C100644 1750 1750 6007 6164542140 12370 0ustar davedave#ifndef _global_h # include "global.h" #endif #ifndef _vec2_h # include "vec2.h" #endif Vec2 Vec2Zero( RealZero, RealZero ); // // Aufsplittung des Vektors in 2 Vektoren parallel und vertikal zum // Richtungsvektor d. Dazu wird folgendes Gleichungssytem gelöst: // // vx dx -dy // ( ) = l *( ) + u *( ) // vy dy dx // // V() = x + y // void Vec2::Split( const Vec2 &d, Vec2 *vx, Vec2 *vy ) const { Real l,u; if (d.Y()!=RealZero) { l = ( Y() + ( X() * d.X() / d.Y() ) ) / ( d.Y() + ( d.X() * d.X() / d.Y() ) ); u = ( l * d.X() - X() ) / d.Y(); *vx = Vec2( l* d.X() , l*d.Y() ); *vy = Vec2( u*(-d.Y()), u*d.X() ); } else { if (d.X()!=RealZero) { *vx = Vec2( X(), RealZero ); // parallel zur X-Achse *vy = Vec2(RealZero, Y() ); } else { *vx = *this; // keine Richtung -> gesamter Vektor ist x *vy = Vec2Zero; } } } // // Analog zur kompletten Aufsplittung wird in der folgenden // Version von split nur der parallele Anteil zurückgeliefert. // void Vec2::Split( const Vec2 &d, Vec2 *vx ) const { Real l; if (d.Y()!=RealZero) { l = ( Y() + ( X() * d.X() / d.Y() ) ) / ( d.Y() + ( d.X() * d.X() / d.Y() ) ); *vx = Vec2( l* d.X() , l*d.Y() ); } else { if (d.X()!=RealZero) { *vx = Vec2( X(), RealZero ); // parallel zur X-Achse } else { *vx = *this; // keine Richtung -> gesamter Vektor ist x } } } // // Berechnung des Winkels, den der angegebene Punkt zur aktuellen Korrdinate // hat. Ergebnis liegt zwischen 0 und 2*M_PI // Real Vec2::AngleRadial( const Vec2 &d ) const { Real erg; Real dx=d.X()-X(); Real dy=d.Y()-Y(); Real fdx=fabs(dx); Real fdy=fabs(dy); if (fdx>fdy) { if (fdx>1e-10) erg = atan( -dy/dx ); else erg = (dy<0)?M_PI_2:3*M_PI_2; // Fehler behoben ??? if (dx<0) erg+= M_PI; } else { if (fdy>1e-10) erg = atan( dx/dy ); else erg = (dx>0)?M_PI_2:3*M_PI_2; // Fehler behoben ??? if (dy<0) erg+= M_PI; erg-=M_PI_2; } if (erg #include #include #include #include // // The basic floating point class can be exchanged between doubles and // floats. The latter one is faster on my 386. #ifndef __TURBOC__ # define REAL_IS_FLOAT 0 #else # define REAL_IS_FLOAT 1 #endif // // A real C++-Class can be used for real arithmetic. Unfortunately // that really slows the calculation down, even though the whole class // is defined inline. #define REAL_IS_CLASS 0 // // There are some specialized vector classes for 2 and 3 dimensionaL // vectors, which can also be realized by inheriting from an universaL // vector-class (but again, that's expensive) #define Vec2IsVector 0 #define Vec3IsVector 0 // // constants to overcome the problem with unprecise real-arithmetics #if (REAL_IS_FLOAT) # define EPS 1e-4 #else # define EPS 1e-10 #endif #ifdef DEBUG #define DBG0(f) printf( f ) #define DBG1(f,a) printf( f,a ) #define DBG2(f,a,b) printf( f,a,b ) #define DBG3(f,a,b,c) printf( f,a,b,c ) #define DBG4(f,a,b,c,d) printf( f,a,b,c,d ) #else #define DBG0(f) #define DBG1(f,a) #define DBG2(f,a,b) #define DBG3(f,a,b,c) #define DBG4(f,a,b,c,d) #endif // // here come something very unlike OO, but its just easier ... // all common variables are defined in the xjig.C file // extern Display *dpy; // the display connection extern int scr; // the current screen extern Window win; // the main window (can be root in shape-mode) extern GC gc; // the main graphic context extern int verbose; extern int texture_mode; // mode for texture mapping depending on depth extern Cursor normal_cursor, move_cursor, pull_cursor, idle_cursor, no_cursor; extern int zoom_factor; // current zooming stage (default: 20) extern int win_size_x; extern int win_size_y; extern int offx; // half tilesize as offset to frames extern int offy; extern int width; // height of image extern int height; // width of image extern int dx; // number of tiles in x-direction extern int dy; // number of tiles in y-direction extern int tile_size; // average tile size extern int shared; // flag about usage of MIT-SHM extern int shapes; // flag about usage of the shape extension extern int shadow_size; // pixels in shadow frame extern double fliptimebase; // base time for flipping extern double fliptimedelta; // added to base for each tile extern int maxfliptiles; // max. number of tiles for automated flip extern int minadjustcount; // number of tiles to start 90 degrees autoadjust extern double flipsave; // dont let the tile come close to a vertical // position during the flip ... extern double turntimebase; // base time for 90 degree rotation extern double turntimedelta; // added to base for each additional tile extern int maxturntiles; // max. number of tiles for rotation animation extern int maxsnapretries; // max. possible retries to snap the snapped extern class Puzzle *p; // Collection of all puzzle pieces extern class GifPixmap *pm; // Original pixmap for the puzzle tiles extern class Port *port; // Port (Display synonym) for color mapping extern class ObjectStack *stk; // administrator object for all viewable objects extern class ImageBuffer *img_buf;// memory for rotating image (probably shared) #define WARP_NO_LOCK -2000 extern int warp_center; // help information to safely warp the pointer extern int warp_lock_x; extern int warp_lock_y; extern int side_lock; // which side (of TwinPixmap) as default extern int distortion; // factor to control distortion of the tiles extern double maxang; // maxmum offset angle at startup extern int shuffle; // shuffle tile as default extern int straight_setup; // offset for straight debugging setup extern int angle; // preset angles for debugging extern int quit; // global flag to initiate quitting extern double GetCurrentTime(int busy=0); // to query current time extern int my_rand(void); // private randomizer #define XPix(x) ((int)(x)) #define YPix(y) ((int)(y)) #define AnyButtonMask (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask) #endif xjig-2.4.orig/real.C100444 1750 1750 1563 6121351712 12450 0ustar davedave #ifndef _global_h # include "global.h" #endif #ifndef _real_h # include "real.h" #endif #ifndef RealZero const Real RealZero = 0.0; #endif FunTab::FunTab( double (*fkt) (double), double from_in, double to_in, int step_in ) { from = from_in; to = to_in; step = step_in; interval = (to-from)/Real((double)step); val = new Real [step+1]; for (int i=0;i<=step;i++) { val[i] = fkt( from+interval*(double)i ); } } FunTab::~FunTab() { if (val) delete [] val; } const Real &FunTab::GetVal( const Real &in ) const { double m = fmod( in, 2.0*M_PI ); while( m<0 ) m+= M_PI*2.0; int ind = (int)((m-from)/interval+0.5); return val[ind]; } Real FunTab::GetRezVal( const Real &in ) const { int hi = step; int lo = 0; int mid = (hi+lo)/2; while( mid!=lo ) { if (val[mid]>in) hi=mid; else lo=mid; mid = (hi+lo)/2; } return (double)mid*interval+from; } xjig-2.4.orig/real.h100444 1750 1750 13664 6121351712 12542 0ustar davedave#ifndef _real_h #define _real_h // copied from math.h // #ifndef M_PI // # define M_PI 3.14159265358979323846 // #endif #if (!REAL_IS_CLASS) # if (REAL_IS_FLOAT) typedef float Real; # else typedef double Real; # endif # define _RealZero 0.0 #else class Real { public: Real(const Real &r) { d=r.d; } Real(int l_val) { d = (double)l_val; } Real(double d_val) { d = d_val; } Real() { } operator double() const { return (double)d; } // operator int() const { return (int)d; } const Real& operator=(const Real &z); inline const Real& operator+=(const Real &z); inline const Real& operator+=(double d); inline Real Real::operator+(const Real&) const; friend inline Real operator+(double, const Real&); friend inline Real operator+(const Real&, double); inline const Real& operator-=(const Real &z); inline const Real& operator-=(double d); inline Real Real::operator-(const Real&) const; friend inline Real operator-(double, const Real&); friend inline Real operator-(const Real&, double); inline const Real& operator*=(const Real &z); inline const Real& operator*=(double d); inline Real Real::operator*(const Real&) const; friend inline Real operator*(double, const Real&); friend inline Real operator*(const Real&, double); inline const Real& operator/=(const Real &z); inline const Real& operator/=(double d); inline Real Real::operator/(const Real&) const; friend inline Real operator/(double, const Real&); friend inline Real operator/(const Real&, double); friend inline int operator==(const Real&, const Real&); friend inline int operator!=(const Real&, const Real&); friend inline int operator<=(const Real&, const Real&); friend inline int operator>=(const Real&, const Real&); friend inline int operator< (const Real&, const Real&); friend inline int operator> (const Real&, const Real&); friend inline int operator==(const Real&, double d); friend inline int operator!=(const Real&, double d); friend inline int operator<=(const Real&, double d); friend inline int operator>=(const Real&, double d); friend inline int operator< (const Real&, double d); friend inline int operator> (const Real&, double d); inline int operator!() const { return (d)?0:1; } inline Real operator+() const { return *this; } inline Real operator-() const { return Real(-d); } private: // Real( long ) {} // Real( int ) {} #if (REAL_IS_FLOAT) float d; #else double d; #endif }; //-------------------------------------------------------------------------- inline const Real& Real::operator=(const Real &z) { d = z.d; return *this; } inline const Real& Real::operator+=(const Real &z) { d += z.d; return *this; } inline const Real& Real::operator-=(const Real &z) { d -= z.d; return *this; } inline const Real& Real::operator*=(const Real &z) { d *= z.d; return *this; } inline const Real& Real::operator/=(const Real &z) { d /= z.d; return *this; } //-------------------------------------------------------------------------- inline int operator==(const Real& z1, const Real& z2) { return z1.d == z2.d; } inline int operator!=(const Real& z1, const Real& z2) { return z1.d != z2.d; } inline int operator<(const Real& z1, const Real& z2) { return z1.d < z2.d; } inline int operator>(const Real& z1, const Real& z2) { return z1.d > z2.d; } inline int operator<=(const Real& z1, const Real& z2) { return z1.d <= z2.d; } inline int operator>=(const Real& z1, const Real& z2) { return z1.d >= z2.d; } inline int operator==(const Real& z1, double d) { return z1.d == d; } inline int operator!=(const Real& z1, double d) { return z1.d != d; } inline int operator<(const Real& z1, double d) { return z1.d < d; } inline int operator>(const Real& z1, double d) { return z1.d > d; } inline int operator<=(const Real& z1, double d) { return z1.d <= d; } inline int operator>=(const Real& z1, double d) { return z1.d >= d; } //-------------------------------------------------------------------------- inline Real Real::operator+( const Real &z ) const { Real erg(*this); erg+=z; return erg; } inline const Real& Real::operator+=(double d) { return *this+=Real(d); } inline Real operator+( double d, const Real &z2 ) { return Real(d)+z2; } inline Real operator+( const Real &z1, double d ) { return z1+Real(d); } inline Real Real::operator-( const Real &z ) const { Real erg(*this); erg-=z; return erg; } inline const Real& Real::operator-=(double d) { return *this-=Real(d); } inline Real operator-( double d, const Real &z2 ) { return Real(d)-z2; } inline Real operator-( const Real &z1, double d ) { return z1-Real(d); } inline Real Real::operator*( const Real &z ) const { Real erg(*this); erg*=z; return erg; } inline const Real& Real::operator*=(double d) { return *this*=Real(d); } inline Real operator*( double d, const Real &z2 ) { return Real(d)*z2; } inline Real operator*( const Real &z1, double d ) { return z1*Real(d); } inline Real Real::operator/( const Real &z ) const { Real erg(*this); erg/=z; return erg; } inline const Real& Real::operator/=(double d) { return *this/=Real(d); } inline Real operator/( double d, const Real &z2 ) { return Real(d)/z2; } inline Real operator/( const Real &z1, double d ) { return z1/Real(d); } //-------------------------------------------------------------------------- #endif #ifndef RealZero extern const Real RealZero; // Null als Konstante der Klasse #endif class FunTab { public: FunTab( double (*fkt)(double), double from=0.0, double to=360.0, int step=360 ); ~FunTab(); const Real &GetVal( const Real &in ) const; Real GetRezVal( const Real &in ) const; private: Real *val; Real from; Real to; int step; Real interval; }; extern "C" { double floor( double x ); // aus math.h } inline int rtoi(const Real &r) { return (int)floor((double)r+0.5); } #endif xjig-2.4.orig/xjig.cat100644 1750 1750 21123 6175502415 13076 0ustar davedave NAME xjig - the jigsaw puzzle SYNOPSIS xjig DESCRIPTION XJig is a puzzle, that tries to replicate a jigsaw puzzle on the screen as close as possible. As in every jigsaw puzzle, the goal is to set all the pieces together. If you like, you can watch the time that you spent for it. Any image-file in gif-format can be used as the source for the puzzle, which is then randomly created regarding the sizes selected by the options. The control should be as intuitive as possible in the way that you will usually pull the freely rotatable pieces at one edge, drag them to the desired destination and drop them so they will snap together easily when close to an neighboured tile. SPECIAL EFFECTS Tiles are freely formed and rotatable with texture mapping routines to give the appearance of a real mess on the screen. Tiles snap together very easy if they are dropped some- where close to another matching tile, when turned in the correct direction. Puzzles can be doubled sided so you might have to flip the tiles to the correct side to let them snap together. If the Xserver supports the Shape-Extension, the tiles can be opened directly on the desktop, which is a pretty show- case, but you need a very fast machine for really getting this playable. (Any ideas on how to add double buffering to the shaped-window approach of the jigsaw are warmly welcome!) CONTROLS The usual way to move the pieces on the screen should be to drag the piece with the left mouse button to their des- tination by pulling them at on edge. The piece will auto- matically rotate like if you pull or push them with your fingertip on a table. In addition, the following movements are possible: click left: rotate 90 degrees left click right: rotate 90 degrees right click middle: flip tile to backside drag left: rotator drag (as mentionned above) +middle: pause rotator drag for a straight drag drag middle: straight drag +left: pause drag for a static rotation +click left: rotate 90 degrees left during drag +click right: rotate 90 degrees right during drag CTRL+click left: same as click middle The right button has actually the same functionality as the middle button so that 2 button systems shouldn't have problems. Only the "drag middle+click right" move will not work in that mode, and the flipping has to be done with the help of the CTRL-key. OPTIONS Tile Selection -file name use the specified file as the source image for the puzzle -side p select the side of the image to be on top, if you don't like the mess with the double sided tiles. Size Selection -w x Select number of tiles in horizontal direc- tion. The Images are automatically rotated in portrait orientation before they are sliced. Therefore x usually should be smaller than y of the next option. -h y Select number of tiles in vertical direction respectively. -ts n Select average tile width. Instead of explic- itly specifying the number of tiles by using the previous options -w and -h, the average tile width in pixels can be selected and the values for x and y above are computed accord- ing to to the selected size. Image Options -ww x Select width of image in pixels. This can be used to scale the image before playing for the case that a very large image is the source. -wh h Select height of image in pixels. If only one of -ww and -wh, the aspect ratio is kept con- stant. -no_crop The image is usually automatically cropped, since many images are surrounded by frames or textual comments. The cropping stops at a reasonable amount of colors per line or row. If this is not desired of if you want to puz- zle with painted images with few color, you should disable this feature. -no_flip Before tiling takes place, a landscape image is rotated to portrait mode, which effects successive options like -w or -ww. If this is not desired, you can switch this feature off. X-Window options -display name Select the display to connect to. -shapes If the SHAPE-extension is supported by your display, you can use this option to let each puzzle tile appear in its own shaped window. The results might depend on the behaviour of the window-manager. The manager is actually advised by the override redirect attribute flag of the puzzle shapes not to do anything with them. But who knows ... -no_shm When the program was build with support of the MIT-SHM extension, it might crash when started to display on a remote machine or X-terminal. You can deselect the usage of the extension with this option. Miscellaneous -no_anim Turns off animation of rotation and flipping, for the case the machine isn't fast enough to make it look nice. ZOOMING & PANNING For not losing tiles at the window border and for getting more workspace, the game has some zooming and panning fea- tures to control the view on your desk. They are con- trolled via the keyboard with the following functionality: Cursor Keys: Pan View Page-Up or Add: Zoom in Page-Down or Sub: Zoom out Home: Reset to original size End: Set maximum zooming to view all tiles The image quality usually suffers from zooming, since gif- images are usually dithered to be viewed best in their original size. This also applies to the size options -ww and -wh. Color Allocation The program was tested on PseudoColor- and TrueColor- displays. On PseudoColor-displays the program might run out of colors, since colors are very limited and it has to share its colors with other clients. It tries to share similar colors with other clients. But if too may color consuming clients are running, the image-quality will suf- fer. You should stop other clients in that case or you might quantize the image to a fewer number of colors with packages like ImageMagick, xv or netpbm. SEE ALSO X(1), convert(1), xv(1), ppmquant(1) COPYRIGHT Copyright 1996, Helmut Hoenig, Heiligenhaus email (for any comments): Helmut.Hoenig@hub.de smail (for gifts): Helmut Hoenig Hopfenstrasse 8a 65520 Bad Camberg GERMANY ******************************************************** By the way, I am collecting banknotes! If you want to join into my collection, get any bill of your country, sign it on the backside and send it to me so I will pin it on my world map. (Don't forget the exact location for the pin :-) But you can also just send me a picture postcard ... ******************************************************** Permission to use, copy, modify, and distribute this soft- ware for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies. other fancy things from the author xcol (1990) - color selector for editing text-files flying (94/95) - pool billard simulation xdefmap (1995) - enhanced tool for setting up standard colormaps xmemory (95/96)- memory with simultaneous multiplayer action available at ftp.x.org and its mirrors xjig-2.4.orig/gifx_image.C100644 1750 1750 6502 6175346367 13647 0ustar davedave #include "global.h" #include #include #include #include #include #include "gifx_image.H" #include "color_mapper.H" GifXImage::GifXImage(class Port *port,const char *filename,int autocrop) : p(port), GifImage(filename,autocrop) { xwidth = Width(); xheight = Height(); dpy=p->GetDisplay(); scr=DefaultScreen(dpy); ximage = 0; gif_cols=0; SetupMapper(); #ifndef RANGE_CHECK offset_rows=(int)(sqrt((double)xwidth*(double)xwidth+(double)xheight*(double)xheight)/2.0)+1; #else offset_rows=0; #endif } GifXImage::~GifXImage() { DropData(); if (gif_cols) delete [] gif_cols; } void GifXImage::SetupMapper() { if (gif_cols) delete [] gif_cols; SetupTrueMapper(); } void GifXImage::SetupTrueMapper() { gif_cols=new unsigned long[GetNCols()]; for (int i=0;iGetMapper()->alloc_color(&def); } } void GifXImage::TraceMapper() { for (int i=0;i>8, def.green>>8, def.blue>>8, gif_cols[i] ); } } void GifXImage::CreateData( int w, int h ) { xwidth = w; xheight = h; #ifndef RANGE_CHECK offset_rows=(int)(sqrt((double)w*(double)w+(double)h*(double)h)/2.0)+1; #else offset_rows=0; #endif DropData(); switch(texture_mode) { case 1: Reset8(); break; case 2: Reset16(); break; case 3: Reset32(); break; default: fprintf( stderr, "depth not supported\n" ); exit(0); } } void GifXImage::DropData() { if (ximage) { delete [] (ximage->data-offset_bytes); ximage->data = 0L; XDestroyImage(ximage); ximage=0; } } unsigned long GifXImage::GetPixel(int x, int y) { if (x<0||x>=xwidth||y<0||y>=xheight) { return 0; } else { return XGetPixel(ximage,x,y); } } /*----------------------------------------------------------------------------*/ #define DATA_TYPE CARD32 #define DATA_PAD 4 void GifXImage::Reset32() { # include "reset_image.H" } #undef DATA_TYPE #undef DATA_PAD /*----------------------------------------------------------------------------*/ #define DATA_TYPE CARD16 #define DATA_PAD 2 void GifXImage::Reset16() { # include "reset_image.H" } #undef DATA_TYPE #undef DATA_PAD /*----------------------------------------------------------------------------*/ #define DATA_TYPE CARD8 #define DATA_PAD 1 void GifXImage::Reset8() { # include "reset_image.H" } #undef DATA_TYPE #undef DATA_PAD // ======================================================================== GifPixmap::GifPixmap( Port *port, const char *filename, int autocrop ) : GifXImage(port,filename,autocrop) { int w, h; pixmap=0; const char *ext=GetExtensionData( SUBSIZE_EXTENSION ); if (ext&&sscanf( ext, "%dx%d", &w, &h)==2) { xmult=GifXImage::Width()/w; ymult=GifXImage::Height()/h; } else { xmult=1; ymult=1; } } GifPixmap::~GifPixmap() { if (pixmap) XFreePixmap(dpy,pixmap); } Pixmap GifPixmap::GetPixmap() { if (!pixmap) { pixmap=XCreatePixmap(dpy,RootWindow(dpy,scr),xwidth,xheight,DefaultDepth(dpy,scr)); XPutImage(dpy,pixmap,DefaultGC(dpy,scr),GetImage(),0,0,0,0,xwidth,xheight); } return pixmap; } void GifPixmap::CreateData(int w,int h) { w*=xmult; h*=ymult; if (pixmap) { XFreePixmap(dpy,pixmap); pixmap=0; } GifXImage::CreateData(w,h); } xjig-2.4.orig/vec2list.C100644 1750 1750 6521 6170525036 13267 0ustar davedave#ifndef _global_h # include "global.h" #endif #ifndef _vec2list_h # include "vec2list.h" #endif #ifndef _mat2_h # include "mat2.h" #endif Vec2List::Vec2List( int len_in ) { alloc_len = len_in; len = 0; v = new Vec2[alloc_len]; } Vec2List::Vec2List( const Vec2List &vl ) { v = 0; *this = vl; } Vec2List::Vec2List( const Vec2List &vl, const Mat2 &m ) { alloc_len = len = vl.Len(); v = new Vec2[alloc_len]; for (int i=0;imax_x) max_x=v[i].X(); if (v[i].Y()max_y) max_y=v[i].Y(); } *tl = Vec2(min_x,min_y); *br = Vec2(max_x,max_y); } else { *tl = Vec2Zero; *br = Vec2Zero; } } const Vec2List& Vec2List::SetAt(int id,const Vec2 &z) { if (id>=0&&id=alloc_len) { alloc_len += 4; Vec2 *new_v = new Vec2[alloc_len]; for (i=0;i=id;i--) v[i+1]=v[i]; // shift to the end len++; v[id] = z; return *this; } const Vec2List& Vec2List::Del(int id) { int i; for (i=id;i but not include const Vec2List& Vec2List::DelRange( int from, int to, int *start ) { int i; if (fromto) { // cut to end for (i=to+1;i<=from;i++) v[i-to-1]=v[i]; *start=from-to-1; len=from-to; return *this; } else { /* from == to */ *start=from; return *this; } } const Vec2List& Vec2List::operator=(const Vec2List &vl) { if (v) delete v; alloc_len = len = vl.Len(); v = new Vec2[alloc_len]; for (int i=0;i=alloc_len) { alloc_len += 4; Vec2 *new_v = new Vec2[alloc_len]; for (int i=0;i #ifdef PINUP_DEFAULT # include # include #endif #include #include #include #include #include #include #ifndef X_GETTIMEOFDAY /* define X_GETTIMEOFDAY macro, a portable gettimeofday() */ /* copied from Xos.h for pre-X11R6 releases */ # if defined(SVR4) || defined(VMS) || defined(WIN32) # define X_GETTIMEOFDAY(t) gettimeofday(t) # else # define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0) # endif #endif #ifndef FDS_TYPE // // The problem occured, that on HP-UX, the type used in the masks of the // select() system call are not the usual 'fd_set'. Instead they are just // integer pointers, which leads to an compile-error, when not casted. // Therefore it actually will get casted by the following Macro FDS_TYPE, // which should usually be defined to an empty string. // # ifdef __hpux # define FDS_TYPE (int*) # else # define FDS_TYPE # endif #endif #ifndef _objects_h # include "objects.H" #endif #include "gifx_image.H" #include "color_mapper.H" #include "imgbuff.H" #include "puzzle.H" #include "cursor.h" #define _DEBUG #include "global.h" #ifndef JIG_DEFAULT # define JIG_DEFAULT "default.gif" #endif Display *dpy; int scr; Window win; GC gc; int texture_mode=0; // mode for texture mapping depending on depth Cursor normal_cursor, move_cursor, pull_cursor, idle_cursor, no_cursor; int zoom_factor=20; int win_size_x=100; int win_size_y=100; int offx=0; // half tilesize as offset to frames int offy=0; int width =0; // height of image int height=0; // width of image int dx = 0; // number of tiles in x-direction int dy = 0; // number of tiles in y-direction int tile_size=0; // average tile size int shuffle=3; // shuffle tile as default int side_lock=-1; // which side (of TwinPixmap) as default #ifdef __hpux int shared=0; // dont use extension as default #else int shared=1; // use MIT-SHM extension as default #endif int shapes=0; int quit=0; // global flag to initiate quitting int random_seed=0; int distortion=20; // factor to control distortion of the tiles double maxang=45; // maximum rotation angle (off from 90degrees) int shadow_size=1; // pixels in shadow frame int straight_setup=-1; // offset for straight debugging setup int no_flip=0; // suppress automatic flip of landscape images int autocrop=1; // try to cut the edges away double fliptimebase=0.07; // base time for flipping double fliptimedelta=0.02; // added to base for each tile int maxfliptiles=8; // max. number of tiles for automated flip int minadjustcount=4; // number of tiles to start 90 degrees autoadjust double flipsave=0.2; // dont let the tile come close to a vertical // position during the flip ... double turntimebase=0.15; // base time for 90 degree rotation double turntimedelta=0.02; // added to base for each additional tile int maxturntiles=5; // max. number of tiles for rotation animation int maxsnapretries=1; // max. no. of tiles that could recursively snap together int warp_center; int warp_lock_x=WARP_NO_LOCK; int warp_lock_y=WARP_NO_LOCK; char *dispname=""; char *filename=JIG_DEFAULT; int verbose=0; int rotate=0; // rotation demo for debugging int angle=0; // preset angles for debugging class Puzzle *p; // Collection of all puzzle pieces class GifPixmap *pm; // Original pixmap for the puzzle tiles class Port *port; // Port (Display synonym) for color mapping class ObjectStack *stk; // administrator object for all viewable objects class ImageBuffer *img_buf; // memory for rotating image (probably shared) // =========================================================================== static unsigned char b[2]; static void my_srand( unsigned seed ) { b[0]=seed&0xff; b[1]=seed>>8; } int my_rand(void) { unsigned long s1=b[0]<<8|b[1]; s1+=12345; s1*=s1; b[0]=(unsigned char)((s1>>8)&0xff); b[1]=(unsigned char)((s1>>16)&0xff); return (s1>>8)&0xffff; } // =========================================================================== static void local_usleep( long time ) { struct timeval timeout; int nfound; timeout.tv_sec = (long)0; timeout.tv_usec = (long)time; nfound=select(0,0,0,0,&timeout); } /*static*/ void do_sound( char *str ) { XKeyboardState old_keyboard_values; XKeyboardControl values; int pitch, percent,duration,pause; char *str_p=str; XGetKeyboardControl(dpy,&old_keyboard_values); while( sscanf(str_p,"%03d%02d%02d%02d;",&pitch,&percent,&duration,&pause)==4 ) { values.bell_pitch=pitch; values.bell_percent=percent; values.bell_duration=duration; XChangeKeyboardControl(dpy,KBBellPercent|KBBellPitch|KBBellDuration,&values); XBell(dpy,values.bell_percent); XFlush(dpy); local_usleep(pause*10000); str_p+=10; } #ifdef __hpux values.bell_pitch = old_keyboard_values.bell_pitch; values.bell_percent = old_keyboard_values.bell_percent; values.bell_duration = old_keyboard_values.bell_duration; #else values.bell_pitch = 440; values.bell_percent = 50; values.bell_duration = 100; #endif XChangeKeyboardControl(dpy,KBBellPercent|KBBellPitch|KBBellDuration,&values); XFlush(dpy); } // =========================================================================== // // some help routines for easy drawing ... // void DrawLine( const Real& x1, const Real& y1, const Real& x2, const Real& y2 ) { int px1 = XPix(x1); int py1 = YPix(y1); int px2 = XPix(x2); int py2 = YPix(y2); XDrawLine( dpy, win, gc, px1, py1, px2, py2 ); } inline void DrawLine( const Vec2 &p1, const Vec2 &p2 ) { DrawLine( p1.X(), p1.Y(), p2.X(), p2.Y() ); } // =========================================================================== static unsigned long start_seconds; static void InitTime() { struct timeval start; X_GETTIMEOFDAY( &start ); start_seconds = start.tv_sec; } double GetCurrentTime(int busy) { struct timeval current; X_GETTIMEOFDAY( ¤t ); #ifdef PINUP_DEFAULT static unsigned long last=0; static unsigned long idle_start=0; unsigned long val=(current.tv_sec%86400uL); if (busy) idle_start=val+15; if (last!=val/5&&val=570&&minute<765)||(minute>=810&&minute<1020)) { do_sound( "440995005;370995005;440995005;" ); } } #else (void)busy; #endif return( ((double)(current.tv_sec-start_seconds))+(current.tv_usec/1000000.0) ); } // =========================================================================== class BackDrop : public Object { public: BackDrop(); virtual ~BackDrop(); virtual void ExposeRegion( int x, int y, int width, int height ); virtual void ZoomView( int midx, int midy, int chg ); protected: void InitFillStyle(); unsigned long toppixel; unsigned long bgpixel; unsigned long botpixel; Pixmap tilemap; GC gc_tile; }; BackDrop::BackDrop() { bgpixel =port->AllocNamedColor( "grey50" ); toppixel=port->AllocNamedColor( "grey60" ); botpixel=port->AllocNamedColor( "grey40" ); gc_tile=XCreateGC(dpy,RootWindow(dpy,scr),0,0); InitFillStyle(); } BackDrop::~BackDrop() { XFreeGC(dpy,gc_tile); XFreePixmap(dpy,tilemap); } void BackDrop::InitFillStyle() { tilemap=XCreatePixmap(dpy,RootWindow(dpy,scr), zoom_factor,zoom_factor,DefaultDepth(dpy,scr)); XSetForeground(dpy,DefaultGC(dpy,scr),bgpixel); XFillRectangle(dpy,tilemap,DefaultGC(dpy,scr),0,0,zoom_factor,zoom_factor); XSetForeground(dpy,DefaultGC(dpy,scr),toppixel); XDrawLine(dpy,tilemap,DefaultGC(dpy,scr),0,0,zoom_factor-2,0); XDrawLine(dpy,tilemap,DefaultGC(dpy,scr),0,1,0,zoom_factor-2); XSetForeground(dpy,DefaultGC(dpy,scr),botpixel); XDrawLine(dpy,tilemap,DefaultGC(dpy,scr),zoom_factor-1,0,zoom_factor-1,zoom_factor-1); XDrawLine(dpy,tilemap,DefaultGC(dpy,scr),0,zoom_factor-1,zoom_factor-2,zoom_factor-1); XSetTile(dpy,gc_tile,tilemap); XSetFillStyle(dpy,gc_tile,FillTiled); } void BackDrop::ExposeRegion( int x, int y, int width, int height ) { XSetTSOrigin(dpy,gc_tile,-x,-y); XFillRectangle(dpy,mystack->dbmap,gc_tile,0,0,width,height); } void BackDrop::ZoomView( int /*midx*/, int /*midy*/, int chg ) { zoom_factor+=chg; XFreePixmap(dpy,tilemap); InitFillStyle(); zoom_factor-=chg; } // =========================================================================== void usage() { printf( "usage : xjig []\n" ); printf( "\n" ); printf( "options: -file : use gif-image in \n" ); printf( " -w : number of tiles in x direction\n" ); printf( " -h : number of tiles in y direction\n" ); printf( " -ts : set average tile size\n" ); printf( " -ww : width of image\n" ); printf( " -wh : height of image\n" ); printf( " -side : lock side only\n" ); printf( " -no_flip : no automatic flip of landscape images\n" ); printf( " -no_crop : do not crop images\n" ); #ifdef USE_MIT_SHM printf( " -shm : use MIT-SHM %s\n", (shared)?"(default)":"" ); printf( " -no_shm : don't use MIT-SHM extension %s\n", (shared)?"":"(default)" ); #endif printf( " -shapes : use shape extension to draw on desktop\n" ); printf( " -no_anim : don't animate rotation and flipping of tiles\n" ); if (verbose) { printf( "additional options for debugging:\n" ); printf( " -a : startup angle\n" ); printf( " -s : shuffle tiles\n" ); printf( " -sf : full shuffle\n" ); printf( " -sa : shuffle angles\n" ); printf( " -sp : shuffle positions\n" ); printf( " -r : rotation demo\n" ); printf( " -8 -16 -32 : manually select optimized texture mapping routine\n" ); printf( " -dist : distortion percentage\n" ); printf( " -maxang : maximum rotation angle at startup\n" ); printf( " -rand : seed for random generator\n" ); printf( " -shadow : pixels of shadowed border\n" ); printf( " -setup : straight setup with offset \n" ); printf( " -ftb : set flip time base (%g)\n", fliptimebase ); printf( " -ftd : set flip time delta (for aditional tiles) (%g)\n", fliptimedelta ); printf( " -mft : maximun number of flip tiles (%d)\n", maxfliptiles ); printf( " -fs : set value, when to stop the flip (%g)\n", flipsave ); printf( " -ttb : set turn time base (%g)\n", turntimebase ); printf( " -ttd : set turn time delta (for aditional tiles) (%g)\n", turntimedelta ); printf( " -mtt : maximun number of flip tiles (%d)\n", maxturntiles ); printf( " -msr : maximun number snap retries (%d)\n", maxsnapretries ); printf( " -mac : minimum number of tiles for adjustment (%d)\n", minadjustcount ); } printf( "\ncontrols:\n" ); printf( "\n" ); printf( "click left: rotate 90 degrees left\n" ); printf( "click right: rotate 90 degrees right\n" ); printf( "click middle: flip tile to backside on double sided puzzle\n" ); printf( "drag left: drag with automatic rotation\n" ); printf( "drag middle: straight drag\n" ); printf( "drag left+middle: pause rotator drag for a straight drag\n" ); printf( "drag middle+left: pause straight drag for a static rotation\n" ); printf( "drag middle+click left: rotate 90 degrees left during straight drag\n" ); printf( "drag middle+click right: rotate 90 degrees right during straight drag\n" ); printf( "CTRL + click left: (same as click middle)\n" ); printf( "\n" ); printf( "author : Helmut Hoenig, July-24-96 (V2.4) (Helmut.Hoenig@hub.de)\n" ); printf( "\n" ); exit(0); } void scan_args( int argc, char **argv ) { for (int i=1;ierror_code==BadWindow) { // just ignore BadWindow failures, since they easily might occur // due to the destruction of windows. return 0; } else return old_handler( dpy_in, xerror ); } int main(int argc, char **argv) { static char *def_argv[]= { "xpuzzle", "-file", JIG_DEFAULT, 0 }; XEvent event; unsigned long next_sec=0; const char *options; if (argc<2) { argv=def_argv; argc=(sizeof(def_argv)/sizeof(char*))-1; } scan_args( argc, argv ); quit=0; old_sighandler=signal( SIGINT, sig_quit ); // // open the display and a port object as a color manager // dpy = XOpenDisplay(dispname); if (!dpy) { fprintf(stderr,"can't open display '%s'\n", dispname); exit(-1); } scr = DefaultScreen(dpy); port = new Port(dpy); printf( "\n" ); printf( "xjig V2.4, by Helmut Hoenig, July-24-96\n" ); printf( "\n" ); if (!texture_mode) { // // check screen depth to select function for texture mappings // switch(DefaultDepth(dpy,scr)) { case 8: texture_mode=1; break; case 16: texture_mode=2; break; case 24: case 32: texture_mode=3; break; } } if (!texture_mode) { fprintf( stderr, "*** Unable to select texture mode for Depth %d\n", DefaultDepth(dpy,scr) ); fprintf( stderr, " You can manually select one by trying either -8, -16 or -32\n" ); fprintf( stderr, " Good Luck.\n" ); exit(0); } if (verbose) { switch( texture_mode ) { case 1: printf( "texture mode 1: 1 byte\n" ); break; case 2: printf( "texture mode 2: 2 byte\n" ); break; case 3: printf( "texture mode 3: 4 byte\n" ); break; } } old_handler=XSetErrorHandler( error_handler ); // check for shapes if (shapes) { int major, minor; shapes=XShapeQueryVersion(dpy,&major,&minor); if (shapes&verbose) printf( "--- using shape extension V%d.%d\n", major, minor ); } #ifdef PINUP_DEFAULT { struct stat buf; struct passwd *pwd; char name[256]; stat( filename, &buf ); pwd=getpwuid( buf.st_uid ); strcpy( name, pwd->pw_gecos ); if (strchr(name,',')) *strchr(name,',')='\0'; if ( !strstr( filename, "default" ) ) { if (!strcmp( name, "Gast-Kennung")) strcpy(name,"Norbert Klaus"); printf( "loading: '%s', supplied by %s.\n\n", filename, name ); } } #endif // // load image an scale it according to the input options // or set original image size, when no size selected. // pm=new GifPixmap(port,filename); options=pm->GetExtensionData( OPTION_EXTENSION ); if (options) { char opt_buffer[256]; int argc_opt=0; char *argv_opt[20]; char *cptr=opt_buffer; strcpy(opt_buffer,options); argv_opt[argc_opt++]=argv[0]; argv_opt[argc_opt++]=cptr; while( *cptr ) { if ( *cptr==' ' ) { *cptr++=0; argv_opt[argc_opt++]=cptr; } else cptr++; } scan_args( argc_opt, argv_opt ); } const char *comment=pm->GetExtensionData( COMMENT_EXTENSION ); if (comment) { printf( comment ); putchar( '\n' ); } if (autocrop) pm->CropImage(); if (pm->Width()>pm->Height()&&!no_flip) pm->Rotate90(); if (verbose) printf("original image size: %d %d\n", pm->Width(), pm->Height() ); if (!width&&!height) { width = pm->Width(); height= pm->Height(); } else { // scale to desired size, (keep aspect when only one param selected) if (!width) width=height*pm->Width()/pm->Height(); if (!height) height=width*pm->Height()/pm->Width(); } pm->CreateData( width, height ); if (!dx||!dy) { if (dy) dx=width*dy/height; else if (dx) dy=height*dx/width; else if (tile_size) { dx=width/tile_size; dy=height/tile_size; } } if (dx<=0||dy<=0) { dx=4; dy=6; } if (verbose) printf( "number of tiles: %d\n", dx * dy ); offy = height/dy/2; if ( (height+(dy+1)*offy) > DisplayHeight(dpy,scr)-20 ) { offy=(DisplayHeight(dpy,scr)-height-20)/(dy+1); } offx = width /dx/2; win_size_x=2*(width+dx*offx)+offx; if ( win_size_x > DisplayWidth(dpy,scr)-8 ) { win_size_x=DisplayWidth(dpy,scr)-8; if ( 2*width+dx*offx+offx > win_size_x ) offx=(win_size_x-2*width)/(dx+1); } tile_size=width/dx; if (shapes) { win_size_x=DisplayWidth(dpy,scr); win_size_y=DisplayHeight(dpy,scr); win=RootWindow(dpy,scr); } else { win_size_y=height+(dy+1)*offy; win=XCreateSimpleWindow(dpy,RootWindow(dpy,scr), 0,0,win_size_x,win_size_y,2,WhitePixel(dpy,scr), port->AllocNamedColor( "grey50" ) ); XStoreName(dpy,win,argv[0]); } gc =XCreateGC(dpy,win,0,0); XSetForeground(dpy,gc,WhitePixel(dpy,scr)); // prepare some cursors XColor white_col, black_col; Pixmap pixmap; XParseColor(dpy,DefaultColormap(dpy,scr), "white", &white_col ); XParseColor(dpy,DefaultColormap(dpy,scr), "black", &black_col ); normal_cursor = XCreateFontCursor( dpy, XC_top_left_arrow ); move_cursor = XCreateFontCursor( dpy, XC_fleur ); pull_cursor = XCreateFontCursor( dpy, XC_hand2 ); idle_cursor = XCreateFontCursor( dpy, XC_watch ); pixmap = XCreateBitmapFromData(dpy,RootWindow(dpy,scr), cursor_bits, cursor_width, cursor_height ); no_cursor = XCreatePixmapCursor( dpy, pixmap, pixmap, &white_col, &black_col, cursor_x_hot, cursor_y_hot ); XFreePixmap( dpy, pixmap ); InitTime(); // create Object-Stack with Background if (shapes) { stk = new WindowObjectStack(); } else { stk = new DBObjectStack(); stk->Append( new BackDrop() ); } // create buffer for faster image rotation img_buf = new ImageBuffer(); // initialize puzzle game my_srand( random_seed ); p = new Puzzle(); p->Init(width,height,dx,dy, pm->GetExtensionData( FLATTILE_EXTENSION ) ); // check for hidden pieces options=pm->GetExtensionData( REMOVETILE_EXTENSION ); if (options) { const char *cptr=options; while(*cptr) { int x,y; sscanf(cptr,"%02x%02x",&x,&y); cptr+=4; p->DropTile(x,y); } } if (shapes) { XSelectInput(dpy,win,KeyPressMask); } else { XSelectInput(dpy,win, ExposureMask|StructureNotifyMask|KeyPressMask| ButtonPressMask|ButtonReleaseMask|PointerMotionMask); XMapRaised(dpy,win); } while(!quit) { if (!XPending(dpy)) { XSync(dpy,0); while (!XPending(dpy)) { struct timeval timeout; struct fd_set readfds; int nfds; FD_ZERO( &readfds ); FD_SET( ConnectionNumber(dpy), &readfds ); nfds = ConnectionNumber(dpy)+1; timeout.tv_sec = 0; double current_time=GetCurrentTime(); timeout.tv_usec = (long)(1000000 * (1.0-(current_time-floor(current_time)))); select( nfds, FDS_TYPE &readfds, 0, 0, &timeout ); current_time = GetCurrentTime(); // printf( "%g\n", current_time ); if ((unsigned long)current_time>next_sec) { char buffer[20]; next_sec = (unsigned long)current_time; if (!p->Finished()) { sprintf( buffer, "xpuzzle: %02ld:%02ld", next_sec / 60, next_sec % 60 ); if (!shapes) XStoreName(dpy,win,buffer); } else { sprintf( buffer, "no more tiles left at: %02ld:%02ld", next_sec / 60, next_sec % 60 ); if (!shapes) XStoreName(dpy,win,buffer); XBell(dpy,100); XFlush(dpy); next_sec=1000000; } } } } XNextEvent(dpy,&event); switch(event.type) { case KeyPress: { char buffer=0; XComposeStatus compose; KeySym keysym; int mult=(event.xkey.state&ShiftMask)?2:1; XDefineCursor(dpy,win,idle_cursor); XFlush(dpy); XLookupString( (XKeyEvent*)&event, &buffer, 1, &keysym, &compose ); switch( keysym ) { case XK_plus: case XK_KP_Add: case XK_Page_Up: case XK_KP_Page_Up: stk->ZoomView(win_size_x/2,win_size_y/2,2*mult); stk->ExposeRegion(0,0,win_size_x,win_size_y); break; case XK_minus: case XK_KP_Subtract: case XK_Page_Down: case XK_KP_Page_Down: if (zoom_factor>5) stk->ZoomView(win_size_x/2,win_size_y/2,-2*mult); stk->ExposeRegion(0,0,win_size_x,win_size_y); break; case XK_Right: case XK_KP_Right: stk->PanView( 10*mult, 0 ); stk->ExposeRegion(0,0,win_size_x,win_size_y); break; case XK_Down: case XK_KP_Down: stk->PanView( 0, 10*mult ); stk->ExposeRegion(0,0,win_size_x,win_size_y); break; case XK_Left: case XK_KP_Left: stk->PanView( -10*mult, 0 ); stk->ExposeRegion(0,0,win_size_x,win_size_y); break; case XK_Up: case XK_KP_Up: stk->PanView( 0, -10*mult ); stk->ExposeRegion(0,0,win_size_x,win_size_y); break; case XK_End: case XK_KP_End: { int x1,y1,x2,y2; stk->GetExtent(&x1,&y1,&x2,&y2); stk->PanView( x1-win_size_x/2+(x2-x1)/2, y1-win_size_y/2+(y2-y1)/2 ); int zf1=(int)(win_size_x*zoom_factor/(x2-x1)); int zf2=(int)(win_size_y*zoom_factor/(y2-y1)); if (zf23) { stk->ZoomView(win_size_x/2,win_size_y/2,zf1-zoom_factor); stk->ExposeRegion(0,0,win_size_x,win_size_y); } break; } case XK_Home: case XK_KP_Home: { int x1,y1,x2,y2; stk->GetExtent(&x1,&y1,&x2,&y2); stk->PanView( x1-10, y1-win_size_y/2+(y2-y1)/2 ); stk->ZoomView(10,win_size_y/2,20-zoom_factor); stk->ExposeRegion(0,0,win_size_x,win_size_y); break; } case XK_Escape: case XK_Q: case XK_q: quit=1; break; default: break; } XDefineCursor(dpy,win,normal_cursor); XSync(dpy,0); warp_lock_x=WARP_NO_LOCK; // just as a way tp unlock warp_lock_y=WARP_NO_LOCK; break; } case ButtonPress: GetCurrentTime(1); // Reset idle start stk->DispatchPress( &event.xbutton ); break; case ButtonRelease: stk->DispatchRelease( &event.xbutton ); break; case MotionNotify: if (warp_lock_x!=WARP_NO_LOCK) { do { if ( (!shapes&&warp_lock_x==event.xmotion.x&&warp_lock_y==event.xmotion.y) ||((shapes)&&warp_lock_x==event.xmotion.x_root&&warp_lock_y==event.xmotion.y_root) ) { warp_lock_x=WARP_NO_LOCK; warp_lock_y=WARP_NO_LOCK; break; } printf( "#### motion event skipped due to warp lock.\n" ); } while( XCheckMaskEvent(dpy,PointerMotionMask,&event) ); } else { while( XCheckMaskEvent(dpy,PointerMotionMask,&event) ); if (event.xmotion.state) stk->DispatchMotion( &event.xmotion ); } break; case EnterNotify: XSetInputFocus( dpy, event.xcrossing.window, (int)None, CurrentTime ); break; case Expose: if (shapes) { stk->ExposeWindowRegion( event.xexpose.window, event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height ); } else { stk->ExposeRegion(event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height ); } if (rotate) { XSync(dpy,0); double t1=GetCurrentTime(); p->Rotation(); double t2=GetCurrentTime(); printf( "Rotation Time: %.4g secs.\n", t2 - t1 ); rotate=0; } break; case ConfigureNotify: if (win_size_x!=event.xconfigure.width||win_size_y!=event.xconfigure.height) { win_size_x=event.xconfigure.width; win_size_y=event.xconfigure.height; } break; } } delete img_buf; printf( "terminated\n" ); return 0; } xjig-2.4.orig/gifx_image.H100644 1750 1750 2650 6172521417 13640 0ustar davedave#ifndef __gifx_image_h #define __gifx_image_h #include "gif_image.H" class GifXImage : public GifImage { public: GifXImage( class Port *port, const char *filename, int autocrop=0); ~GifXImage(); // Size Information int XWidth() { return xwidth; } int XHeight() { return xheight; } void GetXSize( int *w, int *h ) { *w=xwidth; *h=xheight; } void CreateData( int w, int h ); void SetupMapper(); void SetupTrueMapper(); void TraceMapper(); XImage *GetImage() { if (!ximage) CreateData(xwidth,xheight); return ximage; } unsigned long GetPixel( int x, int y ); public: void DropData(); void Reset8(); void Reset16(); void Reset32(); Display *dpy; int scr; XImage *ximage; int xwidth, xheight; int offset_rows; // rows befor and ahead of the image int offset_bytes; // to prevent overwrite when optimized unsigned long *gif_cols; class Port *p; }; class GifPixmap : public GifXImage { public: GifPixmap( class Port *port, const char *filename, int autocrop=0); ~GifPixmap(); Pixmap GetPixmap(); void CreateData( int w, int h ); int Width() { return GifXImage::Width()/xmult; } int Height() { return GifXImage::Height()/ymult; } int XWidth() { return GifXImage::XWidth()/xmult; } int XHeight() { return GifXImage::XHeight()/ymult; } int IsTwinPixmap() { return ymult==2; } private: Pixmap pixmap; int xmult,ymult; }; #endif xjig-2.4.orig/gif_image.C100644 1750 1750 42225 6167035360 13466 0ustar davedave// // The loading routine for gif images was extracted from the gif-loader // of the xv-package. It was enclosed into a C++-class and enhanced for some // features to query possible extension data, which can be used to store // the additional setup informations and copyright notes. // // Here is the original note, that once was contained in the loader // /* * xvgif.c - GIF loading code for 'xv'. Based strongly on... * * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image. * * Copyright (c) 1988, 1989 by Patrick J. Naughton * * Author: Patrick J. Naughton * naughton@wind.sun.com * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * This file is provided AS IS with no warranties of any kind. The author * shall have no liability with respect to the infringement of copyrights, * trade secrets or any patents by this file or any part thereof. In no * event will the author be liable for any lost revenue or profits or * other special, indirect and consequential damages. * */ #include #include #include #include "gif_image.H" #define False 0 #define True 1 #define DEBUG 0 #define quiet 1 #define minpix 10 #define fastinfo_flag 0 void Extension::AddData( char *ndata, int nlen ) { char *hdata=new char[len+nlen]; memcpy(hdata,data,len); memcpy(hdata+len,ndata,nlen); delete data; len+=nlen; data=hdata; } GifImage::GifImage(const char *filename, int autocrop ) : lockcount(0) { first=0; LoadGIF( filename ); name = strrchr(filename,'/'); if (name) name=strdup(name+1); else name=strdup(filename); if (autocrop&&!fastinfo_flag) CropImage(); } GifImage::GifImage() { first=0; name=strdup("dummy"); lockcount=0; ColorMapSize=128; for (int i=0;i<128;i++) { Red[i] = 255 * ((i>>5)&0x03) / 3; Green[i] = 255 * ((i>>2)&0x07) / 7; Blue[i] = 255 * (i&0x03) / 3; } width =1; height=1; data =(byte*)malloc(1); } GifImage::~GifImage() { if (lockcount) { fprintf( stderr, "ERROR: GifImage::~GifImage: image still locked\n" ); } if (first) delete first; free(name); CloseGif(); } const char *GifImage::GetExtensionData( unsigned char code ) { Extension *current; for (current=first;current;current=current->next) { if (current->code==code) return current->data; } return 0; } int GifImage::GetColor(int id, unsigned short *red, unsigned short *green, unsigned short *blue) { *red =Red[id] | Red[id]<<8; *green=Green[id] | Green[id]<<8; *blue =Blue[id] | Blue[id]<<8; return 0; } void GifImage::Recolor( class GifImage *gif_p ) { int mapper[256]; int i,j; for (i=0;iColorMapSize;j++) { int dr = (gif_p->Red[j] -Red[i]); int dg = (gif_p->Green[j]-Green[i]); int db = (gif_p->Blue[j] -Blue[i]); int d = dr*dr + dg*dg + db*db; if (dColorMapSize;j++) { Red[j] = gif_p->Red[j]; Green[j] = gif_p->Green[j]; Blue[j] = gif_p->Blue[j]; } ColorMapSize = gif_p->ColorMapSize; } void GifImage::Rotate90() { byte *ndata; int help; if (!(ndata = (byte *)malloc(width*height))) { fprintf(stderr,"not enough memory to flip image"); exit(-1); } for (int y=0;yWidth(); int y22=y21+gif_p->Height(); int nwidth,nheight; byte *ndata=0; if (x21>=0) { if (x22>Width()) nwidth=x22; else nwidth=Width(); } else { if (x22>Width()) nwidth=gif_p->Width(); else nwidth=(-x21)+Width(); } if (y21>=0) { if (y22>Height()) nheight=y22; else nheight=Height(); } else { if (y22>Height()) nheight=gif_p->Height(); else nheight=(-y21)+Height(); } if (nwidth>Width()||nheight>Height()) { if (!(ndata = (byte *)malloc(nwidth*nheight))) { fprintf(stderr,"not enough memory for image"); exit(-1); } /* move first image */ memset( ndata, 0, nwidth*nheight ); int offx = (x21<0)?-x21:0; int offy = (y21<0)?-y21:0; for (int y=0;yColorMapSize ); for (int i=0;iColorMapSize;i++) { printf( "%3d: %02x %02x %02x %02x %02x %02x\n", i, Red[i], Green[i], Blue[i], gif_p->Red[i], gif_p->Green[i], gif_p->Blue[i] ); } #endif int offx = (x21>=0)?x21:0; int offy = (y21>=0)?y21:0; for (int y=0;yHeight();y++) { memcpy( ndata+offx+(offy+y)*nwidth, gif_p->data+y*gif_p->Width(), gif_p->Width() ); } if (ndata!=data) { free(data); data = ndata; height = nheight; width = nwidth; } } void GifImage::AddLock(class GifXImage * /*locker*/ ) { lockcount++; } void GifImage::RemoveLock(class GifXImage * /*locker*/ ) { if (!--lockcount) { delete this; } } void GifImage::GetSize( int *w, int *h ) { *w = Width(); *h = Height(); } long GifImage::GetAverageColor() { long erg; int i; erg=0; for (i=Width()*Height();i>0;i--) { erg+=10*Red[*data]; erg+=5*Green[*data]; erg+=Blue[*data]; data++; } return erg; } #define IMAGESEP 0x2c #define EXTENSION 0x21 #define INTERLACEMASK 0x40 #define COLORMAPMASK 0x80 #define ADDTOPIXEL(a) if (Quick) data[Offset++]=a; else AddToPixel(a) #define ALLOCATED 3 static int BitOffset, /* Bit Offset of next code */ XC, YC, /* Output X and Y coords of current pixel */ Offset, /* Offset in output array */ Pass, /* Used by output routine if interlaced pic */ BytesPerScanline, /* bytes per scanline in output raster */ NumUsed, /* Number of colors really used */ CodeSize, /* Code size, read from GIF header */ ReadMask; /* Code AND mask for current code size */ static boolean Interlace; static byte *Raster; /* The raster data stream, unblocked */ /* The GIF headers found in the file */ static byte gifheader[13]; static byte imageheader[9]; static byte colormap[3*256]; /* The hash table used by the decompressor */ static int Prefix[4096]; static int Suffix[4096]; /* An output array used by the decompressor */ static byte OutCode[1025]; /* The color map, read from the GIF header */ static byte used[256]; static char id[] = "GIF"; /*****************************/ int GifImage::LoadGIF(const char *fname) /*****************************/ { register byte ch; FILE *fp; BitOffset = 0, /* Bit Offset of next code */ XC = 0, YC = 0, /* Output X and Y coords of current pixel */ Offset = 0, /* Offset in output array */ Pass = 0; /* Used by output routine if interlaced pic */ ColorMapSize = 0; data = NULL; fp = fopen(fname,"rb"); if (!fp) { fprintf(stderr,"'%s': File not found\n", fname); exit(0); } if ( (fread(gifheader, sizeof(gifheader), 1, fp)!=1) || ( (strncmp((char*)gifheader, id, 3)!=0) && (strncmp((char*)gifheader, "FIG", 3)!=0) ) ) { fprintf(stderr,"'%s' not a GIF file\n", fname ); return 1; } if (strncmp((char*)gifheader+3, "87a", 3) && strncmp((char*)gifheader+3,"89a",3)) fprintf(stderr,"Warning: %s contains unknown version %c%c%c",fname, gifheader[3],gifheader[4],gifheader[5]); HasColormap = ((gifheader[10] & COLORMAPMASK) ? True : False); ColorMapSize = 1 << (gifheader[10]&7)+1; Background = gifheader[11]; /* background color... not used. */ /* Read in global colormap. */ if (HasColormap) ReadColormap(fp); /* Check for image extension */ while ((ch=getc(fp)) == EXTENSION) { char buffer[256]; first=new Extension(getc(fp),first); while ((ch=getc(fp))>0) { fread(buffer,ch,1,fp); first->AddData(buffer,ch); } } if (ch != IMAGESEP) { fprintf(stderr,"'%s': corrupt GIF file (no image separator) '%x'\n", fname, ch); return 1; } fread(imageheader,sizeof(imageheader),1,fp); width = imageheader[4] + 0x100 * imageheader[5]; height = imageheader[6] + 0x100 * imageheader[7]; if (!quiet || fastinfo_flag) { printf("%s: %d x %d x %d\n", fname, Width(), Height(), ColorMapSize); fclose(fp); return 1; } Interlace = ((imageheader[8] & INTERLACEMASK) ? True : False); if (imageheader[8] & COLORMAPMASK) { HasColormap = True; ColorMapSize = 1 << (imageheader[8]&7)+1; ReadColormap(fp); } CodeSize = getc(fp); ReadImageData(fp); fclose(fp); DecodeImage(); return 0; } int GifImage::ReadImageData(FILE *fp) { /* Read the raster data. Here we just transpose it from the GIF array * to the Raster array, turning it from a series of blocks into one long * data stream, which makes life much easier for ReadCode(). */ long filesize, filepos; int ch; byte *ptr1; /* find the size of the file */ filepos = ftell(fp); fseek(fp, 0L, 2); filesize = ftell(fp)-filepos; fseek(fp, filepos, 0); if (!(Raster = (byte *) malloc((unsigned)filesize))) { fprintf(stderr,"Not enough memory to store gif data"); exit(-1); } ptr1 = Raster; while ((ch = getc(fp))>0) { if (fread(ptr1, 1, ch, fp)<(unsigned)ch) fprintf(stderr,"corrupt GIF file (unblock)\n"); ptr1 += ch; } return 0; } int GifImage::CropImage(int x1,int y1, int x2, int y2) { int w = x2-x1; int h = y2-y1; if (x1<0 || x2>width || w<0 || y1<0 || y2>height || h<0) { fprintf(stderr,"unable to crop (%d,%d)-(%d,%d)\n", x1,y1,x2,y2); fprintf(stderr,"image size: %dx%d\n", width, height ); exit(-1); } for (int i=0;i=minpix) break; } } if (count>=minpix) break; y1=i; } for (i=Height()-1;i>=0; i--) { int flag[256]; int count=0; ptr = data + (i*Width()); for (j=0;j<256;j++) flag[j]=0; for (j=0; j=minpix) break; } } if (count>=minpix) break; y2=i; } for (i=0; i=minpix) break; } } if (count>=minpix) break; x1=i; } for (i=Width()-1;i>=0;i--) { int flag[256]; int count=0; ptr = data + i; for (j=0;j<256;j++) flag[j]=0; for (j=0; j=minpix) break; } } if (count>=minpix) break; x2=i; } x1++; x2--; y1++; y2--; if (x2<=x1||y2<=y1) return 1; CropImage(x1,y1,x2,y2); return 0; } int GifImage::DecodeImage() { /* Start reading the raster data. First we get the intial code size * and compute decompressor constant values, based on this code size. */ int Quick, /* True, when not interlaced and local Cmap */ InitCodeSize, /* Starting code size, used during Clear */ InCode, /* Value returned by ReadCode */ MaxCode, /* limiting value for current code size */ ClearCode, /* GIF clear code */ EOFCode, /* GIF end-of-information code */ CurCode, OldCode = 0, /* Decompressor variables */ FreeCode, /* Decompressor, next free slot in hashtable */ OutCount = 0, /* Decompressor output 'stack count' */ FinChar = 0, /* Decompressor variable */ BitMask; /* AND mask for data size */ BitMask = ColorMapSize - 1; ClearCode = (1 << CodeSize); EOFCode = ClearCode + 1; FreeCode = ClearCode + 2; /* The GIF spec has it that the code size is the code size used to * compute the above values is the code size given in the file, but the * code size used in compression/decompression is the code size given in * the file plus one. (thus the ++). */ CodeSize++; InitCodeSize = CodeSize; MaxCode = (1 << CodeSize); ReadMask = MaxCode - 1; /* Allocate the X Image */ if (!(data = (byte *) malloc(Width()*Height()))) { fprintf(stderr,"not enough memory for image"); exit(-1); } #if (0) if (!(theImage = XCreateImage(theDisp, theVisual, 8, ZPixmap, 0, (char*)Image, Width(), Height(), 8, Width()))) { fprintf(stderr,"unable to create XImage"); return -1; } #endif BytesPerScanline = Width(); /* Decompress the file, continuing until you see the GIF EOF code. * One obvious enhancement is to add checking for corrupt files here. */ Quick = !Interlace; Offset = 0; if (DEBUG) fprintf(stderr,"Decoding...\n"); InCode = ReadCode(); while (InCode != EOFCode) { /* Clear code sets everything back to its initial value, then reads the * immediately subsequent code as uncompressed data. */ if (InCode == ClearCode) { CodeSize = InitCodeSize; MaxCode = (1 << CodeSize); ReadMask = MaxCode - 1; FreeCode = ClearCode + 2; CurCode = OldCode = InCode = ReadCode(); FinChar = CurCode & BitMask; ADDTOPIXEL(FinChar); } else { /* If not a clear code, then must be data: save same as CurCode */ CurCode = InCode; /* If greater or equal to FreeCode, not in the hash table yet; * repeat the last character decoded */ if (CurCode >= FreeCode) { CurCode = OldCode; OutCode[OutCount++] = FinChar; } /* Unless this code is raw data, pursue the chain pointed to by CurCode * through the hash table to its end; each code in the chain puts its * associated output code on the output queue. */ while (CurCode > BitMask) { if (OutCount >= 1024) { fprintf(stderr,"\nCorrupt GIF file (OutCount)!\n"); exit(1); } OutCode[OutCount++] = Suffix[CurCode]; CurCode = Prefix[CurCode]; } /* The last code in the chain is treated as raw data. */ /* OutCode[OutCount++] = FinChar = CurCode &BitMask*/; FinChar = CurCode & BitMask; ADDTOPIXEL(FinChar); /* Now we put the data out to the Output routine. * It's been stacked LIFO, so deal with it that way... */ while (OutCount>0) ADDTOPIXEL(OutCode[--OutCount]); /* Build the hash table on-the-fly. No table is stored in the file. */ Prefix[FreeCode] = OldCode; Suffix[FreeCode] = FinChar; OldCode = InCode; /* Point to the next slot in the table. If we exceed the current * MaxCode value, increment the code size unless it's already 12. If it * is, do nothing: the next code decompressed better be CLEAR */ FreeCode++; if (FreeCode >= MaxCode) { if (CodeSize < 12) { CodeSize++; MaxCode *= 2; ReadMask = (1 << CodeSize) - 1; } } } InCode = ReadCode(); } free(Raster); return 0; } /* Fetch the next code from the raster data stream. The codes can be * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to * maintain our location in the Raster array as a BIT Offset. We compute * the byte Offset into the raster array by dividing this by 8, pick up * three bytes, compute the bit Offset into our 24-bit chunk, shift to * bring the desired code to the bottom, then mask it off and return it. */ int GifImage::ReadCode() { int RawCode, ByteOffset, BitShift; ByteOffset = BitOffset / 8; BitShift = BitOffset % 8; BitOffset += CodeSize; if (BitShift+CodeSize<8) return (Raster[ByteOffset]>>BitShift) & ReadMask; else { RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]); if (BitShift+CodeSize >= 16) RawCode += (0x10000 * Raster[ByteOffset + 2]); return((RawCode>>BitShift) & ReadMask); } } void GifImage::AddToPixel(byte Index) { if (YC= Height()) { Pass++; YC = 4; } break; case 1: YC += 8; if (YC >= Height()) { Pass++; YC = 2; } break; case 2: YC += 4; if (YC >= Height()) { Pass++; YC = 1; } break; case 3: YC += 2; break; default: break; } } else YC++; } } void GifImage::ReadColormap(FILE *fp) { byte *ptr=colormap; int i; if (DEBUG) fprintf(stderr,"Reading Color map...\n"); fread(colormap, ColorMapSize, 3, fp); for (i = 0; i < ColorMapSize; i++) { Red[i] = (*ptr++); Green[i] = (*ptr++); Blue[i] = (*ptr++); used[i] = 0; } NumUsed=0; } void GifImage::CloseGif() { #if (0) if (LocalCmap) { XFreeColormap(theDisp, LocalCmap); LocalCmap=0; } else { int i,j; unsigned long pixels[256]; for (j=i=0;i #include #include #ifndef __color_mapper_h # include "color_mapper.H" #endif ColorMapper::ColorMapper(Display *dpy_in) : dpy(dpy_in) { Screen *screen = DefaultScreenOfDisplay(dpy); mymap=DefaultColormapOfScreen(screen); cells=0; colors=0; if (DefaultVisualOfScreen(screen)->c_class!=PseudoColor) return; cells=CellsOfScreen(screen); colors = new XColor[cells]; setup_usage(); } ColorMapper::~ColorMapper() { free_usage(); if (colors) delete [] colors; } void ColorMapper::free_usage() { int i; for (i=0;i not usefull } } else { colors[i].flags=0; // not allocatable -> not usefull } } } return; } unsigned long ColorMapper::alloc_color(XColor *def) { int i; long min_dist; int min_i; if (!colors) { def->flags=DoRed | DoGreen | DoBlue; if (!XAllocColor(dpy,mymap,def)) { fprintf( stderr, "\n*** failed to allocated color on '%s'\n\n", DisplayString(dpy) ); exit(0); } return def->pixel; } min_i=-1; min_dist=0; for (i=0;ired)/4; long gd = ((long)colors[i].green - (long)def->green)/4; long bd = ((long)colors[i].blue - (long)def->blue)/4; long dist=rd*rd+gd*gd+bd*bd; if (min_i<0 || dist=0 && min_dist<10000) { return colors[min_i].pixel; } // allocate additional entry for that pixel def->flags=DoRed | DoGreen | DoBlue; if (XAllocColor(dpy,mymap,def)) { colors[def->pixel] = *def; return def->pixel; } // allocate the closest entry if (min_i>=0) { return colors[min_i].pixel; } // everything else failed ... fprintf( stderr, "can't handle colormap overflow ...\n" ); exit(0); return 0; } unsigned long ColorMapper::alloc_named_color( const char *name ) { XColor def; if (!XLookupColor(dpy,mymap,name,&def,&def )) { fprintf( stderr, "\n*** failed to query color '%s'\n\n", name ); exit(0); } def.flags = DoRed | DoGreen | DoBlue; return alloc_color(&def); } // ============================================================================ Port::Port(Display *dpy_in) { dpy = dpy_in; mapper = new ColorMapper(dpy); } Port::~Port() { delete mapper; } xjig-2.4.orig/color_mapper.H100644 1750 1750 1352 6124331544 14216 0ustar davedave#ifndef __color_mapper_h #define __color_mapper_h class ColorMapper { public: ColorMapper(Display *dpy); ~ColorMapper(); unsigned long alloc_color( XColor *col ); unsigned long alloc_named_color( const char *name ); Colormap get_colormap() { return mymap; } Display *GetDisplay() { return dpy; } private: void setup_usage(); void free_usage(); Display *dpy; Colormap mymap; int cells; XColor *colors; }; class Port { public: Port(Display *dpy); ~Port(); Display *GetDisplay() { return dpy; } ColorMapper *GetMapper() { return mapper; } unsigned long AllocNamedColor( const char *name ) { return mapper->alloc_named_color( name ); } private: Display *dpy; ColorMapper *mapper; }; #endif xjig-2.4.orig/cursor.h100644 1750 1750 507 6172526056 13101 0ustar davedave#define cursor_width 16 #define cursor_height 16 #define cursor_x_hot 8 #define cursor_y_hot 8 static char cursor_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; xjig-2.4.orig/tina.gif100644 1750 1750 207672 6172537556 13140 0ustar davedaveGIF87a€ç251˜`FueUçäÒÜïü*-)ÈÎÄ“±Ò“‰e6(·ÁÑZI7"%!74/Ñ´Ž()>6;O/,'qL3‹m] !6!$-|Œš§¿ØóõñuT:ÐàéøæÁ(±ËÑÆÄÈÈØá%!*gln¡–rEBFeD*ÖÖÇdSJvuvÎØê=:>‘³ÙÎοž§§¸ÈÑÞæéÞïË鬼ÅÖÞṩ‰¬©> ÙçñÎÖÙ­¿ÓSC<+R?.8'%äíò––chOJNG•”ŠÖ ~Y^Y^[T/Á¢}Œ‚lY:ÌßîVSLåЪy]J^lxˆ¡µ½ÅÈøùøN4#cE1ïöùŽªÈáåÞíºž‡˜ª…bOµ½À©®§GKTÙÝÖ¿ØîT:?CLÛÙÄ·Ðæ˜¹âxS8W\`Ÿ¦ k{„†ŽÅĸ‚dR—ž˜Ÿ¸ÎcEƒu`½¼°-"0I71–†Ÿ¼v}~²‘m GB<ŠdInuv'cQ=qK7ûüý‚\Aîíã!–°È,€þý H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊLxÈ_Í›6sâ¼¹³§ÎC@mJ4(O£E“š”©Ò¥y:}JµªÕ§:³JÝ©µ+ׯ] ªª …lÍ‚–’]X»vÚ…ipãÊ÷ÝiïÜLsÃnÞ¼}ùæK¸°áÃ+~÷×Íß¼ÉÓ H˜!Eaò’:u™¿Ðí@‘'Oþܹ㘱׈ýšöëÚ†Ú½ ÿÐý.ÐîÛŠ÷*Ç«×í½…÷BŸûÜ­Þ·Æ%!ž.qà‡þý*àƒÁÀ±ÆÝ©u€}­ïÝךOþ·oJð×R’¿?ÿÿC€ÿ  ü ƒ .¨„‚ &C],ƒ7ƒ¤ðC ©½‰5ôòÅ_ÔІ$~|1Ë"®è Çp°É&Çtcü0†¥\há@VX!DZè7ÚxSŠ6N”âÄ“¥8e)Þ,8dHà~¢£\þ·ß|èÔRæ™ÂâFv™¼RÙ²„!uÐRAªa…2Ðôé§Ÿø¹BŸ+z@{óZh-+¬à^£Œ6Úè7‘Jêè ß\:Ÿ¥Œfz¦žb*ê}Ÿ’jªûé @j~¤Igþ™3$’¨Sëä*@’|áÀ¯Ò8ƒ"0|ð :dùß71šŸ©ÐF mE>è ÷=«_}Œ"êè¡zé¡ì‘[(¸è¦ûÏjº5Î8h„ˆÓÊvTÖãðù4ÿþ Í  M¸í™Ë¤ŒnÊ-¥;š)·—Jl±}÷Õq¶G«1ªø©ºÎxøá y†+ÊêpÂË0ϱ«$Âü  ¥)†± ( Í‚K+ô´ø ø µ >û,·õ‘ë^Âè>í4Ôé‚ È¡Ðb—»™´P #œs/-æéË/Ÿ ÜgÁkõÛNË×0}ˆ2]¥v3M©þˆ¹-·üu¡êëÔZ˹B‚2h¼ Ç-XìÄ Æ¬L®e¨ÃÊ5—&¬&ìüÁ ]ð÷ñШ+_³Í®Þ~Ù.m&}x3(¹oÃW5¸nóž5»j®o AüP/-øÞ)ÐXüN“¶À†Ü;îå–›°ÜÛNªgß°£´×ò|ù1Í:Pñ‡$(€$.Ÿ0A;ìp ;`Ì©Ð1Ï M¾À¹ÑÀà€7sÀ1a,UUèhw#•Æ$hÿ0낺 ‚ô“­1ån‰:|Öµ.‚Ëz¼W ýěݼƒ-^›½ê0‚BOhS›Úµ¶·uë[þP[ØÜ47òaêƒG4Õ˜öÖ½&Ž)pxh¢ Y©Ãê˜@ãô€üéAp˜Ü屆~æUÀÙËñ9EtÃX)¸¶ìc7ˆMðu÷씆7îyðaM ¤îD8HÜ¥ÐmW#ÄŸ|ó «ÑÂ×êu¯šmZ˜"ÿd¨p kA|ÂÕ°ºÕ‘|û™k×=î±v›–η*H ~g´$pµœ`X ;p¡‚$L®;ÐÃÈ+þAXtÀh¬è@äàÝNÇÇÕI«| g ßÓàJw%<'!ƒƒŽv¢ïšðD„ F1ŠeTcøþ -hX6ÜpO™ì“"yØ6O’j‘"e¸>ÒQ|âôàøÊgGòýGQìU $ñ*|¡e'Ѓù—„y ;hÇ A`fì•h¨h: š]P€¶(X;g–° ŸÝ”P¦ˆr &<çÉä%  ¯BˆˆÁ ¦JÕ©‚`?Á~`ϯU#ç@ž%…³õ)`ÔÀ5½§Uo”ßú·LI»†²Ò|Cu"ªœªƒô¢ m¨Á…,"#¥$¸ |y¹ð *]„pá?:Èo Q ‰õ«4ËXƒ0Ð+7ÆÓùѨ¨]*¢Ð&Öb@p]ØþÑ ø0U>Ø6)(n‹QŒ øv \PâZ<~ÜÑŒÕ&8ô'Û6°Fµ•jA WCQ;N¡V0ox»k 7¶ÁVêÈÜ °Àv,öežYÃö·ƒ  þ;Á& ŽfÒ s7• È3T½dÎ"- ¹;×Z>`Ê…º€ˆyƒÚàC 4ÌÛbÜ 7ñ n0ƒ¼ Ä3À¶:Š{Vƒ Z8®8fÑ‹YÔ ÃhD*|ð ‚”unxÞt{Gä^Ï«ð×]Ãç´ÄÀªðà x¦°(Ã2Ù3`¡‹üègÖ°ƒ9˜#¾ ¸Çþ Ê€I @4jüUM…õQèôÀ ê+óvÂZ '>€h§;• ©bhÚH6tÛá1„øÑ~Aˆ70Ü‚ ô´³   È@Ž\ÍcZ` 5¨KXÇv±`(ÏŸGH†2rHˆVíº!„Z\Ÿ¦©íÒ>oÕÔ)QëT”c4ˆkÙ`úË„ *h‡h+V¨c 05GjUYÅC#¨™0<Ê9aÀ¨F£»ó³)ÎPÖLÖªPh”èD;·cˆ!‹äâ’ø RPéà«.H8<;ÝN ´ó7ÿàMħAê%+ _í²ÊZÈЄôþzÊÝ•Ò[£\%wMÉòñyw>1Ä~€€Ñuàúu™ÖÀ„Ïè 0DJU@ûi;ñ@1 ‰t ƒV#ˆº0jvÀ©sNÇÈ:ÏÄÇXV•ÊR…v¤è²ó6ßù†ô ñˆ,„¸ßÎm .=ŠA¸@žò¼&Íuà`t8ÒáÀ |à qe¼ã€E fh a ¦¨C+8þO¼èpz%w›õâš°%ƒÏ×í^”C?x>tè`¼|ŨGÍa—ÁX„Ã<èÐøíÀ%-³:âqŒttB1œQ†Ì~éæÎzga ¬7ÿD¸ó²ô#D{£ì)p‚¾þýè\xŸ7 ^‹ñ—ŸàèÇ4=ínwx:~0m½»@BÿÀÆðŒþ?C bð Ë` ¼Ð àc±æ/JÒÓI˜7Jíq.çÒ”"l¥= eôdY2ˆS«ò³€-³ÿ@='*P?Vf?êp÷0éÀ ¿’· ° —°E°ðmÍ×|ðmÂ’u0À¡Õ#1%Ù÷„cðúFi÷Þ— …pb¸•!J8 ˆ ƒ ˆ0†ðŽ$hèmH…TîQB(J» ]à^0W˜Ï~(ù0€¼` 8þ•']ÐCrns.(T.¸) E7ÛÕg£WDñ‘7Å&eœ–ä¦sP?¹rk 8p€¸ Š s°çe04x 0°mF#p ¸Ð æÀ Âà ÍG‹ÂðmçÆ@ø–c@ʸŒËx…D@Ìøâ~)Ðo)0p¸5wƒ # ‡†@àTW&æ”NêTólT“NnCxÞàY@^ }ð‚(ˆù0  à†x§ˆÓåC#.£(U#5×37õlØ“ÙS7×ãHe,4Њ+EŠ E;` € êÐ ed+@ #À 4謀ķ4` þ·à à`HçB8u:y@a€#N@…|H…DðކvÛ¨„SUwx†:0†É†oø†&DBUc޽ókåRBìøÐp„Ðð(óX cðèøû؈˜€ƒVŒ˜yà2õ75syPtEJR3Nî„ÖÕðå ’ƒ 0˜Ÿí€““+ó@0éàfÀèéP’êpF€;`U ¬0ƒ7, “EX#8BЗIø…SUbçT´9޳BuxBÐkè².¸Y—ìA•mèwí¤ÚàÈ™œzH–YÐg)?ü¸ˆøcÉVÕIuþ©w‰5ŽH=ÙdG7àTµ@† ð°¹sñ3'?/C 3õÓŠê0) ¬ðmFÐ2kpm›¹ƒe`à@šÈwšS÷90 #82Qøaƒ@›ÀZEe&e"s@Ž †]¸ó€IeŽ„4~÷wïԔׄ‹6ÚGò˜vX(ˆÿ×jɇèÌ#kÿò/›D] 7 ¢%W0œá$BMƒ0»v×$ê9a 4Ð2‹@Š;_÷ ©°k€R °Ë‹ñPßöm¬Pepe°tÈp ÷0ñ@ %€’7©“u* Òà Dð|Ç4 7zsukþR EVNLåp:`zñt†S¥#£pU£°ùV {˜ñø Ðvþwÿ÷™à p£‡àq°C#g¨è"¤¹™.ƒ²¤_ÇgzPŠ6 â÷Ãbe¹b9ðɰLhú‚ 0iviv÷PXû) FPs 3Πİk`’é0§fÚŸ°’ýi31² S€„Ìø§Iv VT„ @À®´¡~w¢(z†V[V5Á\–vpkÇvù¶©˜Š©DÙœ€Îùš`£çqCɰ£Ò£XÓ€W¹»Cƒjd¡ôdÿQ!ô¦ Ú°$†#S°@ÿ•Eê°jö‚U0÷ þm —`kðƺlq0Ä0ú‰é ³j:· °’`“SG§h: * º üÀ/€ˆHwÅ—s8;eâp´©æ¨U¥¯Áµ*V¶)¦b?°b?PO£°°v7€vr;Å }KÍ™–ðÀ  @þôcAÆ£‹ØC×ed¹‰BmµT¨8‚$NÒad©}EI!æv/@ü0´è#ðÆš+;°ƒ:ëQPt00 s ¬æ@ P逦¬`+YEÛvEP’éà¬àðmü‰´’`á¦@¿r 3bDP U›¤t‡ºw) ¶UÅ  a þà[½…d[ e{pÁ•i[•p.Ф@0ëÆ[|ð$OR ;û‡Ÿª¦p ›€}’C˜'¢ÛÉ›Wã4e‚Ò¸Nà±ÙG–Eù¶þÖvÍÙÀ¹ÐœZÁ/ð›Ð 7ce¥¦'{ „' k€ ,;cª™£ØF|´[ F³’ÐU@ _Ä€’³‹t³K¦4P±+ ÇŒ Ä@TË-òoFa1P¯µÅºE¶P|'†%6Å*¦!Xµb£€, &‘›&WÓ†w€7à¾Tb!LÒ$SB%Êh–öè‡ú¨°‹¿¨Ú'‰typ5öwØ…vhþövoÿʇ7°©mÇÀyÛÀlÇv!–o÷Vo¶Ub,p åu€WÂËö’Ðj pÈЭñ0È ŸkP¶™FÐÊcšÊ’ດ™®lé0¦@ 3h™5s“5r#3@:×”Sb†Š¦a†[”60iÍü̾E½W\kË”Žôi ðiÐëÅr„ •Z g¼ ¥P·|%èë±ÅP3*ˆq<ª÷+kµGx ÈN^âµ r$ç\ )à$Ù‡vP–›ú ˜jЊŒ… Ì}7ð ÿ¶aG‚!gˆ%ÉòTˆ°Uì) ;l6æ 39׆ ¸€²k m¬@þ%_PÐ ´ÜÊÏz¦&\È@ËÚŸ-Œ- Óñðƒâ)ýFDPb†}¹5ÅPi6p§bùªUµ¶ãÛi4'ã+ÃÉZˆö¯î«@0†W¨ç{Æ=â u»$ì{}Å·3ú 8@¿öKV7 ç† ÷T]p$S¥ÎN@–Íèh.ú |È‹l…M’û$Š–$Hâ *Z ØØá8ŽgB&ñÑNéQ7XæY& b/Jð¿½À¦+ x0gÿ% `¬·P_kp $mU­@>=ƒ³kÛà ºÓºÍtÀÃ0}Ëiz 3Ù­Ýúý ?=x`WÔG ƒ©:2†ˆ€>4÷µUüÜ[e\·\–‰Ívëœ €æ­ÆÑò¹R² ‹ßKRoëü˜€s-ªþuMVG@.@·d·„¾Èqë¯qëȺÉr$QE!J€M@p>L•ŽíááåÉÞW :5¾9WŽT€¸ˆ3?®âU`­÷° @l÷à ¢Ñ ¤\3FP}p :ž™Q€ ʺ°ØÂ3h%°·` F0p ©Ì dà 8 Å)6ð$Žßø`åˆÔíÄ„þÀZxȆüÀ þ¶oë}’–V^½Ví¤U¢$ìj|!å샰$G‚[œzß   |»ßþÐîö[Ø;w¶UUK)8ØTÑïön—ŽQƒ•êxNúçoÐ樗)ê³ u#0ØVþ·PѺ÷Ð i–¬@ c*Ó00„¶—@äÎà Æ³ ¼-| q:|Äñ¬kð¬ñ ’° i+i~J7ðÑw÷Vj«gèaßž Ï iù¶OLbR^aW¾ ö:\lÞ”W% Â[Pâ$û¼hN€!ø¾#fßý8 ¦à·8zŽ 2F¯ôŠåðÔN³cNW#ry,±ðâC•j)H‰Ä€@ »üb„“þ‚@Ðá@,úD@plFd3Dt@HÒü:­ oTãÉbd˧ÌgŠim4µã77Åøâ®@þî¸å”¡î„ö ¡Árt¡¸«!ñ°«åÈZ€`É¥Zó†·gÎ+&>RÀô¼ðzá…\:ÍfŠšFDžNª"ʘ ¨£œ‰sÌR°¢.¹jf4<¡Š*îqæÿnY`Ž[œY +#XAuæ ¦Œ/ðB¥»^Hƒ‰®û&o0(;@0HL&«ügùøl¡ù`²2¿›RÀm,cR¢‹Ò¼ñâ™2˜ˆgÞóF&oÔ¼áß|cx|ŸãT9äˆdšÓšŽù„£ì ª.2„= Z ZŠA/[Óæ=1U£fóžô†bnCÓ6þÌKq˜aŠrð€ÄÔt&hõ’: ð–«(b Áz¬tÀ)Á[œñ:,[„Ãë]³"æµ'LVtÚI?¨hׯ°E¤;uy û;½*kAdƒ6¤ tþÞ€I¾ C 3€ _ÇöED %L ˜`‚‰È‡Kém¯M1zN8Š->.ãqðLH:B¤KÈdChHqtZr)&D SáèYÓGHÊ%—GŽ7¾·2³¨MrÌ@2¦-uPB¦AFY§ ÒQ'c]`tNH€[pæž:™ãéG Àþº“¯¿Æ¿™Š]Ãv@‡K¤##øIþä&t¬ ""C^ò–hdO=ÕqÈßFqÇ ƒ KzâÐ1'QÏ€pŽ’„TŒÉa@LÒ×h¼ƒ~Å` e™Äßäb¹‰I dRŒ\<ƒ¨ûÁÄ*V'å$c³ÃÓsa$ ¡c„-yIÕä÷ðf)¨YkF,ïèYÏÐHKåfcØa>#ß9Éx´A`£A¸@ ISGx‹ì@mk˜CÚ±€"dm q(B'4@JèCèDâÀ“Ìa“q°…¯n¡“*\"¿ â€6øaq`Eq7‚£™’Ap·#Òå¦JÉpþàÅödæqùfšÆl`YBX”)1'cÈ Ë”‹ Âe '"R@ß!ur2ÅêäåÜÁ @€'º ½.ª¦5µÏ}ŒÿÄT¥0å mxÃR;³”kÜã°çÑfŒe„XápÕBE  u˜c\þ·ƒv$àq0GJ‘«ž¤ƒ•Ô24p[ÐthGº’¬K,à·hG*²²IŒ ³Àà@‡ £ ÈáÁ@¥L&]0H’x¹ÁÆ (1—|ç¿lð—Sd Ip°½Æ=^,…iø0†\AS)‰ÍÉþM"]/&)pXo‚“ ^‡‰GÈ„ "‡/zq7b,ž¦^ © Ø3Úh7[ó—Û@é¢)°'IÆÏše`Í‚`!æè层ƒ((ò ­á÷8pJRõ`¥5½iRáÒ­u¢Í0ƒ`†>˜Û`¤-œFHB.`÷Hˆá‚.(Ä#µxjaKŽ@CI‰A×;Û“/Õ¥™m* §Š’ƒàëgˆãà(àIÌÛh#yÏøT ~P "˜ÜÔ gpé„›=lJ¤SŽ ‡QÌ@¬‡3œ|(Ë$Œ®ÃÝ$M\Ò XqP¸ûÛ nS¼\ ˆÊ{„òVÄþj>ã/ˆñ§ð)Ÿžñ0²,E”ÎÁÑ · h.þG‡*@rt`.0AR\Ø‚ ” Ÿ3ª°\›—XU[@;èp]Bvr lƒ'³‚`„0|xÁ AUŒà+1€Ðj•€%(9æ«„)Æ º9*D&ómêßf°Lx²7H«ù] np`»©®~Æ R ™xê@#™T5‰ÄÕ!cŽ G5äó$(õÑ%l\nt„ź!Ä3<ƒçðq; £hó© bó¡s5Ø Óê)!"7ŽÑA>xCT†:´­îàíhDZ°áÜíh†-ôe®þµ#…, ŠÀÈ"A“úé ®{‚5¬¡ø¡R½kQoÜà/˜óvÌÛž_¢d2½Œ6¹,\Ëôv1v*bRÐA@ZºTµa‹»róî¡€·ôOË„7æô ”È:;i£p夽-g>þÇddR¤ë4UMàÊ!þæO#n4wAŒvW%¤ ˆÊÞž ¨D h÷Ü€7Vò¥šÅ¨½èÅ0 1 ¸…¹'0ÇJÇïz‡¢Ô¨dýB gà£ÞΨ· 4 I]ò;˜G*’P1œ±°ñÂdÇ,<æ# <Ð.‡$é2Û»{ˆxƒ9çþ¨ 0L•0àÄäܬ™ÿ¸º˜°Qˆ–Ò+¼ql œÁ#"Ĉ0 š"ÂÇQŽª‚UÝp3NíòÆp¡šÎ !Ó«ãµÇG@‰Î%íÊ£7%Y×_Èž‹ÔÚ@¢¤]c ?8G·ð« ˜ƒX[)¿‹¼£K ¿+ApЇtÀŸš‡KH¼Eðœ8òƒ!’Û¡íQ*ÁPÖùQØ€Ms’eÒ¯$±"%aÌØ™Êr½Ç9bë‚OK»’4½2'LÖQè=p0ràx†8)µ:é ã§}Jž(¼Й“øþ „9ˆˆøŒ£ËÉ —gK˜ˆª{„1èŠÀ€~rÊ¡ÓQ2ʂӽÞ@ߌCoÀ˜‡ÛJŠ  s0z`}@J˜€—2ÀÔ´$z $JP)g˜ƒÀ…Thchqðœ2©¦,( ÖJ[Ú“Œ›3Bt’fJM¡1k:d†N˜I‰‘Ž+Ð:„Qx¾89LÓ«L4oÒA`ü/ßH¢Â:¾CP… ‡Ú3ÇHhÜQÈ û‹Kœ,œŽZØ,Ca‰È—K”ÑóX£Æ#' 4"7I­Ô:¢I)Ãã¡«ß(¤;€<¼ þèNJÄy©|©‰‚´¤…ÔH|)J0‚(˜€5( TèÃ$xI‘GM#´-I+ÊáF qòo“†Ž‚!‚I˜ÐÉ!ZÜÀ™„GP qògKoØq* *4°bЫ’Àó&¨KÁªS(,ÖÁ €@œSPØŒ,¹‘®ø¡_€b­"ªCß(†)ù:¼ Ù¬&ù+sºî ”.Ø™%P‡yh‡8ÄLLEÔ‡+£„-@úY·H¤LDŒÄ›:èÃy`‚hhœ˜Â9Dð€¹rùœ|(°NœÍEQØ$Ñ|¸Yó8(Ï„ñ I I}†ªÓ«ØÐ)ì&ø|,§QÓâ 9v‡ ø‡“Ä Ì eP’)qnþK¥ãÂñ@@°8ê™<|ÐÒ‹póДÌ2¸|È‚àÙë&Ùë™É:A¯ÂóË´(:%À¬˜>¼„ V ÌXȈôÓÄ4HGÔÉ„©”º„Ðc˜‡X„@¡Ë‚ÑšÉÕÔM•IóϬ æ“*IJ)™%’0¢| ´F¼|’ö|%4¬æÔ˜iÀ€ÌÊptP†tœ+ÑîÃ?Û“.ð¥ wá"x© PB¿nÒ:9µ± ø,’ÈjáƒßÈD¸hÀ1*ƒ$ ƒpLBµ¤¼KÐJ’€N„B4Ô…,2\h€FþpT˜…e˜òTuINMÑ‚}ÍIˆfˆ… ð¡gÛ€NyQmY[""ÑÛ31(°\X4`Ü´núÐr˜ÿRNf\§v:I]ÌXêûB¬"ÇnypÙ“i{æ»Åº ¢1 4ÜYˆÂ‰>{Ú€Sùø”t<> C>àˆ=bŸ>œ‡”²$\©Xaƒ,„í„¿[ sˆP\˜<ð„ ˜Eš¬ÛýœÅ!ß@‚\xßNé”ešXP ˜`0€j œ²´‹úäŒÆx5j»‘AxÊ!|ÓQøQYºŠÂ\ Pø\ ]Î@ŒøUÜô /b¾  >.×=Q:c¸„¸þ¬¢=/’@a‚Àß}Äy£ƒ±}Ba‰\0S>ðˆº€«Z &h‡yhþdÐgÀjˆƒíÅ¿»âPÀ‡Pø{Ó€§™O(ÑÖlÍ-ãN|˜ä™ß@À@€c0ø ~¾ a F`nä?n,«!Q®\+O{Ys2=S JL+‰Ÿ±ä FÕ‡YâF¾#€w²3 ¨N|’+Ä :‘¨6šŽpÄÚäÙËE|²ZóL4¥/‡@„›AÆ¢Á*‰q ,#þˆZHbH”^0†{¨Hð‰±ˆƒ½Ã‡4kÆæ4@¥x@s°Ho€X˜1 âZ¼½rþ”ŸIFÅ0F0€ýõßrpçýíßýþ]†eXRxº8…jˆg@ä@X¨™hŒ'Q€; øÍ@Ç´Ú½E»4ƒ9¸M‘ÂÉB#‚“m…"]Ž'²3 ˜BP,æ›Â•Mœ)â¢A „wxihp|ñ1´TÙó¢ˆÅ¦à ^3ô®”y#ò¡{ r‘”œÁª‚(8[숔ùµR¨-èX„`shH¯e6€Hƒ¯öê¯D °•«A† P‡v¸‡Fð~ÂmçpgFÀOÙO£ÏëcF(‡u(‡rçþè?67~µ®’ ÊR-€çn`üe\ZKhXÒÉ9É!yè{¢F’ßp͇AþÁJ­ fJ®U85'ªÙvƒ›£gÊJTþUdõnåwPåA˜Ž@%ÈiñZü9tÀ3`²VÚ¸!œ›91ðÁ@r:˜]£ˆ/á%¸ƒWƒs 4X€ùZJ °þêòfÿK‡¥¸8` s¨)ð_¾æë¿^€Õ&±Æº0¨† èëu¸gîÁ€:¦lœ«ÆeûLÍpýÅ_7þÌ»™°ðÇ‹¸c*ÜA{±’àX¥dŽ|˜#Ê`ߨn…¨×y¢Ž#´ÙÙ‘œc¾Qp¡+A‡êD„ÇóÕépŽˆ±kˆˆ¨Ú\$=¥JºÂþ&%¿ã0]D × Ó"2Ó1pox*÷<âZø5mÀ*¸6nÀOòZA¤„ò6oj z€b¬‰Û¢c˜&ƒþ­ó;¯søúä™÷<ÚgÀøïrPßß)(ð)€)ä%5ÁÆB_´°QXFè_Ȇh˜ßÐtù­p ÷”\0 gãLNž¹-0r.¢‡yPLÆ“=mUpÎ'V8hÃàŒÐ;I>`dÕ†'K‘°Z܉ˆãaÇ8ˆnÙ{|<[N9…yá’†Zºr±yl<ÔÉÛÌbˆÅáçd¨và7s #x)jè꯮׮¥\©"XþßExlFì<ÏkÔ<²Û  WElHôä;æ°ºvèœÛÐ8 „ƒŸ‚Lÿ”N!š î” Î†Ž÷”Î4Œ£ŽB˜kõŽNö‡Œq"ÈÊ>¢|qøäuçÀiÙ%ËïD*Å/¹'«õ ®“SJ1Pd->5-=6Qžˆ ‰Ê$‹ðˆ5$D¸+pƒH $@†@¤‡þo5?PHl 6‡$¸€8ƒJÐöC‚9î†;7€lpS«õŒÏ(ÍÖÿ‚‚/‡0FOtFÿý¾›h°p8Ά÷E‚˜øÇކhx_MOž ƒþXQâ‡\°ƒT6þð™,gŠBääØ*‰"‚uoN 8Re0]惡rÒ÷°yDÀùF¦AÆšÒVþNÐ’„› «suJ¥±|ƒ‘ÄE+P /*-hÖ„ …ð§€À! OÄô'À†¤‡”2‚¸sÀ›w¸ç†SÈ„Wø~Ðßý-‡@hE] @¡Ó‘âÙ³ F1 RNQ9S²M1Ñ­b /6nŒöbÈh¹"‰Æ"Ì”hHˆ<ËçÒ%"0aæz‘-ÛÆ\:sÝh3KË|‡æ:á Ï–âÕ €¿¨QhºãÁŸbŒrþ1H¡ƒø|QlÐ?BèøðéBH4h„u9«„P\¹€¼e±º¸k{¾³!EŠ ^fD[²Å’æzt¢ZƒÆä#’Å[­Z.¬C˃0¡ ‚Ή{‚¨¡d„ž>J¸©™³¬ˆ­"qÖ`wæ2`ÈP 4e œÏ²äJH¢Ac7 ̵!›‡åʱˆf'›Än&nzDâ>’gÄÍ‹”c¾|)óå3¹DsÓ ;ô Óý÷Ì# V†P˜Ô3Õ4õ”TªÂÀ970ó̇¹è„Wƒ ÈXƒ 2ÊYi­Å"xá%—|h–\þ3ŽUŒV€Éõ/ðÂWQß#¢C1†!äN|`€"|¤ ÃãXA'¤pñea¢‚IìGEÌ%”˜£œàÐ35E8#Ü È¨“ &•èA6WpG=ž|S/l°Ae• IT.Ù„!ž Ñ (‘DÙxåHÅô©KH@Wi þ×YDì” H3Ñ`.Ÿ‘”§ÏÜ”e7dÁÒ­æb¡Juˆ#â0à Lbè Œ c!Veµ¨ |xs‡\9bÀ3ÎH]ÅàðW·„`PL.c€0â\@>ò’cÖ Üš”YðqÇɬÁ`€Á þ¤ÌE˜aºÖÚBÀ¶€3³ÕFIœøè#ˆwÆ!2(€Å)§èqŠ ˜\q7õÔ#J8á$“Ì8ºÜ¡Ã ûÉô ’*¢H•òÍsišS|¨‚Ú?E3ü Õ]¬8à`3€BOüeqL vCa7| eBVÃ/¦@Õ!ª0 Nþ‰1 µÙ‘5Yf‚µcy“–ŒjÙÖŒqu‘B“Ä?: ’Ôˆ`‹—X ¶4]Þ0–å)¼’ \H!¢?€p„ðD®¬.;;,`§púPCMø€SD(¶„‚ðq 3Á-˜127$pÉ…@þòÈd„|ü)«ÔCÎËtŠD ”ÚñÂyYº‘ª¥š*ÎÙMÜè×GM½Ì2?ü`/¨U‹“¹Ì€&ã¨é¤õpJ2D,¸¡*ˆ‘Ð1°E+ °×Þúf-ÀáålKáÐ8>,JqÚ£ž±äE.ˆ¸K¨c—â0v„à‹§àéÈ´0œáŒÇ“ÞÈBÖÆ5† ¢¨Ç9‚"Üq@–ÚÔ!U¥”¡l¤U`A ÀŒXäÂ~?X†~À‚|5‘Z > µhV5Ùf`™,ôG(Y ŒL‘6.(ÐäX 00·| þÔ— \pA в l Làþ1 >x /¾leV6” ¨èºAâÒ.>¼K(–ùÁN1ºBà³t'â—(ÀÍ„œà\â…Ð:\1н+-JÀΤ ‹q`‡ñþDn¨ ®ãø F0zQd!;Å@Ûx l`8°N¾ DVˆÄÁMi€ÕVj“àG V»ÚŒ0ò@šA ~ô$@BúÔþtR NšÏSù ÎN¬¡SaE G0ÅÞ"ª¾…€@„_s>€sq*`–Ahc€°*4С ­h•:Š,Ç·ÐR OwÆ+@ ­þ¥+Ô &Lråf¼™D»~óˆBH„lÑ×uR¸%8'†ãp{`²_l&X‚`‚ŸPAr @ëade#6ÈPhÊR3ÀÁ(¤¿l@j AdlÁI°d´7fU«>ÉЄÔÇÚˆO29«[5ˆ¦0É$”¨ SµIe*ɸÀ?¨Å–¿ÝIu‹`$+Å«î=@Tj¢Ž·)Ðò¼ð¦RB‡ @Щ–\€ dð/'ÍÓŽ›s­@0¼y×}<ÒûpÅ¥]ñ`4Ãø l;×Y„NÀ3M“çr€ Œ‘=ÃêX·OôSfþ4㤇ƀ޳TˆÔ ð¨(hD'K>ä pÂ’ ™È iUE_°©š¼/¤&øA  ”µ˜ì瘸ýóÉXÈ)kkîÆ1 éFKÅ \  8Kló¶V–=—-ÞD»è=\X® ;|‰æî5Ëaƒt¤óáÉL`G?:Ò 6âÁyépì C3BQj ¸ŠP,¬pÑ !0o²_¼&¸ Î3ÏÄ&îg?¿¸kn¡õ¨É÷ðx<)'ªIü„d“õyþ›ÁGZÕÈC}€ éX ‰f­3±B¸$£aÙlËM`— ZÒ²JgQþêBö쳚«i©Q[ö¬w òèYÑv޹“[m` ½J>蓪\ ¬‡‡ë(ù p3ÒrMð]…Pi_šÒîÈEî î$,ðÔ$Ï"Øv˜ø"Š]ÍX_:WxÀˆßz{þ✲‡ÆÆ  ñÝ`O2öHt’“ä×$v(•ª>pc©ýà‹DOEq«[’~ Vbãv%ŽÉ¦e’2ZvʺìÜ/WרõB3üe0ÕAÈÿ2ï௃¥~‚l¹ eÈØõG}œ L(8ÜÉQ£…‰jpë(Æ}Óæí¥)‘ç%‚˜§I˜ÅÆ|`€2þ îÐËÁëMVÉŒÉ`ÚÀë˜ÌTjœÁ€ œ4Vq0”JðÄ¢€Íò½€epRe…MdCÜA ´‰ÄaÒN¬Ä ”ùÉÊ«táþ Ò½Àù1×T¨ ܌¢Œ‚ ÈÜ‚Ì‹Þ ¼ñÁ½,Ä]”(Ê­SÚŒ žÂÄ$ € Êé¤* ÂP@8Ù•]u\¥ižX 99Ø^õÎ:]X 8hÀlP‚$H‚ °*¨â¨ ì k<, Á˜„˜1Ïj =@®íàqC%ÔéÄ ðÈèDæ žý€FÔ£§Dã•Eã5¥L 4EåÃ6¾@N™[—‹TCñOÜKRÌG} ^g@ˆò=¥PÇ#pŠR´Óà#bCó‘j¬¸Æ Â7ÃYþšUbÇIb%j^ÃA3Œ"ÀÉ`Þ2ÀI:L$=PÂD ˜$H¢Â¹#𠥩`^Ò\k¨&„ɉÅäfeÂ3LÛ#”&W)€ÜA ¼Â+¸ƒÈœhAR"%¦Ê%ù%Þ5îÏPÐÇl "åЂ7jˆ#¸ƒdÀD‰Á‡œ>þó%Ý£¸£Å=WMi‚ \†É]q^j¦Y`Ç•gy.¤ÃH$œÀ =Ð5ØÎ{âFnH˜GªÀGº"йbܧ ‚“¸BJÎ¥k¨N?ù6pC2àØ0ÜÁ+è9h‚&¸C/ˆƒÌB/ôB ôBþÈ.enžÊ >S -%K@#‚LÔt¼@ œV ˜B´‚7~crÖÌù(e5öÇY†áò‰ßuvG€ …QP.äÃ+PÀà JPÞ“>]f¦•çxvžyh% ¨^ÑA'h8¸§nPÃ{ò†nÀ‰Bë±C+ò'*ˆ$*ôå¥=À"öeŒI븆>5ÏqpÂ8ž4Õ< $´A ,ê@‚:Ô@£Ã"¡'õ(þæNHD4ðC=©ÍŒ:¦‹ý@WŒ‚ý´@+Ôqö”; Z¾j!” éN©¯ÌcwÄãÔă¶àÓÉœ˜Ü)•jž$n^_V©þyäyV¢¦ A;88„i{ ™Âç{¶ %à;¸‚+‚¤*~¤ë ‚Ž #ž§+”$8=Öð €AÁà ¸@=ˆÀ…ö‚”A#@¢Ö@䫸k ¬ ˆB’®(ÔpĵŠÿX]Aä?Ä?Œ„¬ìOZ,O|”}”8¤ê/ܨ?pHZj3šr!A­†eñÁÂR,]Т(ßYB]wðX.h¼’Ž ªFë„“]"䀚§y’gynÜ^âeÇ%B3”À´Vk{–ébF+èë¥"¸."* ]î*Ðiëì%JÒeë ”Õ (¤À2¼BÌB¢¶A þÁÌ­¿ÖÀ€Â¢J*0ÀÁ‚RM s>ÝGÜ„øðÃÄ‚¥„Ä>?¸‡mbã§R5T.ýœC+ìAÈv™?\ƒ;,MM…oas^–ã^FWìŸW¤@< Ù ÙE ì#Ì)Ì-ØQçm©¥Y¢¦'ðbš–æ@3Œ`{@{’©¶R+°=„‚G~ä~F&b½ .b8ë€Î¥8µ‰ pCü¼Aô¿>ê¢Ê­¢Ö€‚)Ô@ƒ1B*@*|äC,A4@N<ÔUa4¨Ê¨ÊÄA,@#‰ŽÍ5æTTCTÃ9ЂæòT—þõ€rZ§Â~„s„¥<‘åƒN,м¹€È€d×ê"‚ £ÐNÔE.è¼. Â0b8IZðò®V Bí¥q¯•B+8Ldµ*/|ê†Fƃ,L>ôì¼)¸º"]Ž ØÒå³RÚî–­-žj`ƒ¡z@‚ (´0ûâí"ð‚ä/ L¨/„ƒLì34ðÿÆþ1Å.°”1”QŠìÏ·µ(ÛzSA¼‚on—9‚AÒµJÕøØÂ>Šò°0 ˰*NdD£Üª„˜Ï¨?’I\ºAb\¦/ÑZ¢A ±^&+%Bë(êÃ`*/ó.fþ›Ä2Ó>`êgõº"ÆŒ¤¦Ià\~íÙÞ^˜è0Â0 ƒ¢JÁ¿–¢ª¾^h+ÌÃ<$A#$AƒüÀÿþïP^Ù#ˆ>C£!ËJ‹~›e †@ÿ@$[p»CæZ²T8‚&TƒÔÅ!ù˜Ô “ÔÔ#hUNÞvd…*Ä!G·²òñ å:Ü—tfDà71–ö@ð2ë1.kš%’“-°Á`âÆ|f+%D CkÜÂa^+54oPí sA 1¥Áôk[é²/–-yRbNæbs›,¹,|=Ö+†«Öz±5c\#î®ëdœÌ:DôÂY'4´($êôÂ/ÀÃ2Â2d@ ôâ ü€8®HTìG8‡ ˜€ÔØ )€(Lƒÿ,'Y xÂúàÁ8,:£+¸´À¢_°b×0¶c/(?ÓGÜË¢ŒK§ã¤0r¸6x8y…¸Gg…‰P8ÍŒÃõÉ€'AbàÑ-ŽÓøyÖ4.[â³ Á-è´µ¹þ¶²‰$àF0o›è·.¹›j±ÖVé\îî€J9B¤,öÀ0D!ÅVÐdÃ:ÈÁ/Ôƒ…ÈÁ9ôBÌÃy›µ!4þ‚1,’ñt¬Ã:TðŽà€ÀA Ã,d} B ”Ð5 ~Á/ÁÁ$¸Â'¸£[Ã9ˆƒ5Tƒ8,W”R„Swd|½ rÇ× Ká1qR1ŒºÉ›üd(ˆö‰#H$´Õª4Ã@âÐzÞ±æ2£'–ñ®ÿå-Pð´0C-œ€n°Áp£ä·R¯3(%."•c%’ç]…@ˆµ?P„Û›@ d ˆCdÂ2d ”ÆúÁ:Ç#T Ø#X ˆK5ˆ@*ä#<(´€É@,‰6#ˆ8kjÄù±öaÆŒjZ Fl¡‹\µDˆÌãþÔU² IK±|'óyvˆbÅøÄÜÀG7plxñh ̘ڼñsã†O'G‹=zFÂn… ]‘Ê¥Bˆ'WŸ¸ººoß®_¹ áêµëW±û:˜ÝwÖ•X!m…ä°E =zÔôåÕN¯>Jôô±‰ƒK»3¨P9¬1bWû\¡ *«+˨´zmû$„«!*$ (ÛhÓS‚ÌÊFeÔ l6M’+–Ò‚0 ÄI´.6ÛðÞ¼EAÐÄTµg¨,{ñ‡8ë³Ä1zá°Ä¯^iue¾Qð8øøÊrZÆ $rrŒË˜| šY Äþ\7fÚ @>´Ñm„"ª˜c*æ†,.ન¦ª *«²ÚЬ²{ë« Çë±ÇÀ:ËÃ'⺅ j£'€¾øÒë/6±!²ÃKì0Ç„â Ä:C¬2ÈÚâÊ*­BÀ$-ì0m´)1¡Üy†ˆM¦8& ˜ÂÛ‚¢¢ágn8“n|P#aÄ™E„ø^©$—\~XÂqܱ&ˆ)^X;î‚,Nz&¾ @%“JLÙc½‘C“NÂ(–øð ¿ Hu𿦻iŒûtIÁûœ €d®˜“+¨²C¬4 IJÀVÄ`!+¶È±zþ´å.¿ìr±/}è¡„h+LGTÀãÆÚЬ±«,ãjį´êªª'@iÒ„ÒLˆ’…0ÊaÁšWfá£I6 C‘u–X"ˆ%a!š pH‡W’Hb–äÉMÎ9Y0E "Z(Ä”ðP š†~À‡~aQ1H#1`É‘ ªÑ¥’Ž.õ§MÉëô¤¢BiPgêoO¢ü{&,J›RøxˆSÀ€J*\+ j2p‘ 1,Å-‘X±Æ –ÄÍRŒYiÿJ'¯hÿ¢‡ 6°G8 T|ô • „$1kË2ƒŒ³ êÊ(“c¡1Ë)Ç“^ée€Iˆ­OþððuX˜"ƒ ´g9X0áp‡ XFÎ)Ä1„‘RÉÄ€^ø`ºjpx&‹’aÉÝd1l?é‡Vêh¥€˜g–¡æ”Nzä¥Paa¦ øðï™ü{ä¦bœX>Ô¡,†7&tšªð>’W`ÏZ‹Øõ½> kÕwë‰nÁ‹l´hÑ/éB—ó¶3lë0|óÖ¶ô6,ÏdÅGO¨@†„vÁ) a`„" ¯n˜ÀžF<ñ8ÙL‚ŠðÄ:L0‰r$ å0Ö§8ÍÉ5œÓ"†1‹Fì`ˆ'´0 *|ÊJ¹ËB`A2ŒˆaŒÐ„àƒá}䪘þÙâc3•@ &>™ €ª÷äâz9CP¨Šâ  €NÃÕÈW•¾ëW^û±<«GBØØìò¢¤MlÐ l „Ä,2€<𿆠c)0+kÑJ0QPdÃ6/dD9>Oˆ£o@à|Á‹Ü$ba$d`vP(eȈÀ©†£ñÃ"ð` ø A€á(µpª| qw&[É+Æá9Ђ´àÂzB’)ãuj>[¾)¢* dD•9ïƒ D¯YxD2Àð”[AÍB=ÈL踵õåqŸ“TË×|”ƒPÜmø“V![„ ,䀌d þ¾åM#*¸‚ÌÚÈ<Ð ŠpTO™Â1R*üamPDld“‹|üÀSÀ%(YPÃ8-#çpá:Ô@ŽgLÂÌÈ€".wŽÌJ'3Ù!-,áçàÓM¡žõ´‡fÜLÉ3øÓ>´¤?¤òÏ©^°'ëÙ¤œ¼ËF’Á‰6>­qìA*s•#ÔqwÔg?í—ì`Zvñ +XA¶³5‹ÔXh#߆¸dH¢"J_WÒ—•#DBW8Cø Â Ñ‚بÄ**¡ ѭóøX ¥ÌINåX.ÃäPh"âÐD/R^L‚ë þÖ¡‹Þ9 2pÁÇ^Pšeä#“…V×S¼ša#ÏhÉ(ÀéSí‰dÏà]>žQžòÌgµ*Ä­rUO{jh}—µ#ûÈ>½½¥G¡ˆ‚‹þ Y òEv!dcéÀÄh Û’lˆ”ׄW* ®!àzÀÜÈBåñþïLN  äOÍ!ÖÒÁ rlá ×1¶2ˆ¿Š$S‚¡"T [À GÎ΀ÎB%T@: V"ª>ï LÉ<ÁfÁ¦à˜€ŠloØvŽNB£ÁxÁ|à@a–½„‘r x)ÀÖbf9ÅÁOü:ýE:§3L~ Âáa;ÓLW>ãH¸‚û„e±â3"À€ÁR4ì© ã±÷‰ØaÒÁ>Óað?×` Ò“0ÏJAß‚Â+äA±…"/(@¢‚! hDì)²Â*z€*Âþ .`¨ÀäÞ ÁÖ% @ÄÄà!^)…#vN6‰ ²a Ö!ö€: Îa%8c¡‰´=êà’ó#–óþEÔ :§2:¡5:µ#¦@N²¸@|¸€2À%3Â%×ç ât4 è^çà^õõ“_´Ò[ôË’FD:4B,Rõ‰-²&+zà+pÌTÅ!Ö²d=AäÀZ¬!× @(‡#X`X@x!€¡ikȦ€ò`trG!&æöDhˤLÖÁx9“ÔÎA Ôà y§v  Zs#†“LÎ¡Ò ºÔ*Ö+ði¯¸ÎÕò ËÖl 6Aó¡>þ @£Ü4ÃjîGäaÉ%°`N Òa 4à^áø´_mApñXììköA0aOq·¥añ¬1áÒ[µ¯3 á>êì zA4!§Ü¸˜~Ü”\؈` ê¡ä  \06gcR°ÁZgu!%„VhƒLaˆ÷R,ÀŽ÷9¢_¨ò“ ˜è„4 z#ÜÁzËð3®C‚EÍñ*4ÔlÊ7òáËáè £²!£ èŒnŸ øÕnù’_øø´O× `û‰o*’ .ÔÁ$¸ïÎ.ð´B.÷¡3éª8؆þAò@!VÏŒRÑìàU!g˜ ö Z7Ò8{.‚1¡”} ZAEn‚0‰xxÕ’õ_FN8hs§ ìàwËXsŽe ({»4ŒÇö*ð ±BÓ¢† ¤¢|Eˆé ®Ø¯Ê¥ìПØÕGÚ¡ÿטOݹO·! «!‰Ä)¸ àA1(@²‘o&ã$ æ&>r=£f3¯@Ç8ˆB ²áÕ¡˜` Ê!@™ìBQ' †€¸bp™giH'¡æ¡| a xZ r€0x“àˆ•ÔÀ†F#þ¢!‚U™g‰(‰ò¤Yvœy‹Áö{ݬ+a¯@#›¯ ``J>&¡à Ô¬}§¹2ØòÝ4C€ÚaúõÑôožë91-Ì-Ê8ô–Q% 2:à C34B1á4j-1©H–a àÈšNüà"ÀfÁ²á×^°£ ¡@z†dCUe48s•3´Ã & a˜Àêfƒ6‚i[AiýÁ@a J#|:™yCH…s™‰›e³ª œ±—3Ò²,¸®Í®âB Ôì ö€’€¸Ô #’àÕ¬*4-Œ©¹‘ ü*þ,è R Û:@Û®« 0­1¹æüìšÁ&Ô1u¿]a¿)àŸC[þ9¡:j®  ¡Z@àÁL L¡rL aˆé„6bé jE'÷  A„` –¸ Ø„¸tnaxa~aõ˜À框Jçj•²*Iå ~ú§ƒ•7fé¤W¶¸Y™ˆ@ àú*š»Ž©3C£>¡*"€ ή{dƒÌ0â¶W´.ª-ÄÄR‘ Tn×â è Ô|žÒ­ÛzÞº.¡£nø«GŠ"(P[€þü¿ýÏR]A‚)u-è  àá2þ z@P´Ú€µz €¢as‰€ ê ꌡf[F_V(ŸAç|÷˜aÅyÁ¥ý Ú R†-   ~!ǯL X‘€‰Ñ¨‰Û†o’ð É@¹3‰‹¿Z+˜ú @ÍBÁhQˉ ’WÄ9Ú±º¿U!×+„Ò\Í« çùÍá›Î¹æ}&$ à¨ßû]ÐÙÐ-ƒë>c|Á¡*!4N¶L! p Ü¡ò€¬!ÀÑfÁê` Ú€eWV%†‘6Jœ(Sv`}ÅëÀ~aº¡vHOòžþ …}™Y˜(‹û&eS6—.B>*ºÖ*,5Œ1$>! "à>!ê‡ Vk’›Z¡ö T ¹¹º¾4õ (µ[£=¥GpAÍ›žßžžçYΫ@Îé½2&ØÀ C%036пy,ï ¼Cà ž€ Äá°µAŒ¡– I à:³Äa˜@ø¥µò Z› ²AeY ZõçŸÁôSY‹2÷ºÁRÁæ¡L`| Æá¨«zÙ¤À–98‡ª6kt½²>%ˆŠö@ܳWé™»4ê3>!æ!ò‡^•F¹Ëø!Rä÷@ûþiª;“(à3Øò}±†ÖýÜßí·Íò­ë¾î/ôî@ßâ È`aUB‚Š3gP¹êà*˜+Wû\ Ù'äÉ“®žT¨âb.\,´šQ­R…$ Z-›8²ekÉoʺ^Lj.ZÔfʤ±2Äš”!h>"Db5+_>fÌvµ‰?u’ìYT)ã.ˆÚ㣀¿±c¹ $ôç$¦JÛº}Û–¨&… ]Á„7„Þ CLìÓµakwN"–¨â¡D™$á5¯A„ÉŸ>1¸/&½¨ü>YÈp¡‡O ͖ê·ªTÙVÅ–k×ͪ4kÖNHDþT¨$>QAB…py‹½¯á“ˆ¾ù^ÄÄ‘ã™ZfÔpÕT#wÑ ä2¿\üD‹…^QÍ:×2mŠè¤gŠ>CBt¾ÒÌb! 3ÃÌÃËó€BN=ãÀSɼT@ÖX׸3E>Ïñ 30c!\¾Dur›é…"EUpM\DŠa‹1£ØbŠË2ááG/y²ˆ1’L=HTQh£)§[; 8å²UÑl±Íf[nì ²¥nX`A*€qƉöPEù6Q‘EÇÅW8ò‹Z`S/­ÒË“ èxF!Þ3“¨eX¢î5åTþ†e°T,ô†!J1CèÌ,1„YUI=ɬ‚ …ô Ê!ªHx–}*ua‡Ï|èQ¹ì‘J!*pTÁ‰zÂ'qÀ5X:T>…Õ˜l‡QzãND˜J*¸°ã™_~–$sBÌãLRºfå6­‘ûškí˜ÁΖX°C‚$QÈ‹AñÖYEË}Ææ^xqqÅäüPOžu4ÒçZ>EOùE¬ha‰2e˜†æ©£kqœŸ~þýÔ‹šä‘‡){lu.§QÁ©úãˆTZ)c´~x-t\b¯)B\4ÀÀ9Èî'-Qn9ªTÄïõ·”£ßcþÌ ó´ƒ‹gú.䛾BìPÄ=·XI¥•²M9Ûº!pÉN(¾HŠ,_L𥙵Ë\¿(BW"Å&aLºhQ 6u4ÀD{Gûl!OÒÖÅMÅ‚ñ{‹fžÁ…˜CJè0‹´¢‰&R@‹)AP¡‹œA ªª²ŠQ³îŒûPÖDÀpWpä«^'nÝŸhB¤³Ò÷LOùH”ǯEÔSÓÎsÏ=',°5.]Kä-›caK3UºvKú窫n»XÅ_ÈOÝQ°Ñ^\væWgÀö °+ì©p‡5 &pƒ0F9ÅgInrÊ¢\)çž 6eƒ´XR7þ‹E0ÁÆX„)@‰ ðxÝz03³ÂB¶«T¬hÅ¡·,JÀ -1šdD@„\'Ñx^($¼€Í3”Q6”¨Ÿô„½XÀ=’°ƒK´£ íh®e†}-§"BH–Ò–®+½±öÀ‹ÌñIØM¬ „>B ÍtÆoÛKtÎ@@D@'8°T%`4‹gQ*j”QÔ&–(díä‚ïiˆ55R&ÈÜ!CíX† ^ÑS$ vŠÐ„‹\$QRó±]îàâ³=ØåwÀóñs…`H°Ã ¦0ƒdcÎŒyŠ‚Íþ¢$JYÙœ°€ÜbâÜΈ :”±t`.Ì`†1RI6h;Û¹ÖGÆs²Ã_`ÝâQ??â£XÀ* ÊáAp…`ì0 FÂŒ Å$)­Ibb†áfG;ºe…²>ZJæDºÁd¹ 0Ä0à± c´¢¸€´pnXâ µ$KÍAmJ.V·sK;”WD`D¸¹ ÄÍ|™)ÀP‰&jÕš‚‚XŒ²”M^²‚êð"8ïN3^‚éç8Õ‡O7ªo6ølÛmèæOúõÑ%0D…þËDºJEÀ¢”Cçh~(vÁŒþV ¤¬ ²ŒjÒÇ9íRŒ, XCîh„LÁSèb@°©§ À ÄPh^.þ3#,rLCŸÔXç0„„g`u¦S‰¹"¦™iÀP‡Ä¢G—H9Šu7;Ö¸4Æ‹_äÞZ/QιR©­)/úÞ(W*‘q½—@†$ôøO>òµöÁˆ‡ß8,ÜÀUbŸµ?Ø£“­˜³‚ª³K2bQ»Xs±ˆeã:ÈÅ(Zq)ôâdš¨Ä+¡‹ƒ`éiYÜa ¥Š’JJPX̱Î¥yÿ¹&-Ð߀9ÕDÄË ^"0ð"±×µ‘bn¸þeÚCkSÑ·¦¯¶€«¹êª^*Ý‚¼ZÆÒ%ª0/ê±~} 2ÌP_ûb¢¿ûÝ Ñ_¦â'!sÖd'ÆÑ‰iYKÓÙä,µFíYAÇ+ø0¼½@m#òЈB¼¢¦™ø6x!ÛÉð)Ï.}쳓æ%ï(H‘~0‰%ˆÈ¸Î½ Uóòj95 Hy%'ˆkÉ e‹ðbÆYÆ2n®Äîò°µL^¸ÊS]—Ä{ýI‰xÃò<…×æã “u  W†çÈQÌÈÌâófË îýôÙ- ä ¢|Ø@.‚ w A š/¸AŽˆÀþÜðbx–žD>>5zZŒMCaHFûŬ ÑêjÆÇx)Às÷@©Ãì9׹ދ¶—Ö[Ìcá '±áªå—ü¼äã6&ð^IPB¾p€4â!‰f˜:ˆÓqg^D`ðÑ5 q}kpëzäëNÖ[0Øîd-Aäp…gˆÁR-‡Ä‘h,áߢ¨D8¸ñ .¤jU4“#¢‡÷ùÔÇ«`E8Ô“ÃD£ÄÕUSÊqªšè *(€¬~I’“œÝK˜Ç ’€ù•—ñËÆ–¹ç§|®¸æE×{wžK쨂&s7µ. G€­ Jêþ„|’Ó`ž1M)õÈÄ r‘…(àÓ(>D M c TÐÂ/Œáƒ:pƒØ€¡¦ÝÁ…/\>ƒ¸¨+Ø”KíšCëXjCŸëÔû*ž#£K@ág©—œY¿Â'ªÕéÔóp àÄrŸ'WæUlc4FÍ`¦§su“z=Ç ø0×ME´ÜP °Ð2yGIùǹ“umÁµBÙP«µ ¬õ€‹ØÀ Wð LPÚW¼` Æ Q²CwÂ(-v(ŸV]ÒÂAlÑI2"K÷~?tò—qr{°àQ·{¼h¦pXTõ `þt°r,w€¬Áž'eYF‡·;G7Â0m¬§=ò^è…u`{y Vçt%øt&h¿|•eT’ÄçPä@ºð o@ð€€ Êtð@ áð •à•À@‰=p3s R~ÑsEÂKÕC9dRB)Æ]ðjxñCrgW€ "·ˆ…8AºGrðf;v"Op f€ 0"l¢÷VHsëÕ—òóB7²à åè”Pë°‹ð „×Õâx”3yåF+ëÆ|6hštR"ÕQD ­À>` Æ€@b ‘1\ð @V Gr@‰™Ð ÜþMp ‰0[åÿ=Añ(š#J‹²GÅMHˆ>$'r"0˜ LW%@Äçy62“Áh´À^xUš"Òx BOÞsNÁVFa$Ne4^ãlU€sï5/²Øs¶ÐÙ`a ©àíÇO7†çæ•2uN‡]”~™”šð\ÅU IL @0¼0¯ ™p¯ð –ØT@ä°P€ ŸàŠrP2ÕõQØAÃbU9Ó""u!'@FUÀ’ˆÔC_è ^ù•úGó+ )Ò±×€šöOAIétN®yNêt ¶à”bV7åXŽñ€ Põþ@`‡V̸Œ÷¨]ˆÈ™…˜d!uYã–á°j0M@WP§ É  É ãà™  -sä 2J7[á—(³’1ƒ1›dA–ò1:DŒ°j$r\Xá\ÄUSh6“ä– „— ÷•Êåý¢ìB𓉠ý€š‰p ö@¡Ó¸šöà^óB P޲°z¾ ¸À_= 4Ô™UW‚,hýy*Ú¢“>]…0«ÀB•À nW n· £2*=š º Þ© ºÀ u@ &F3(ö›–ówŒâ˜K±3D   LÎU0ÍÅ’X˜ {°HèF†¸6 \šSþCó! ?i¾± º§ºá¦ z 60/á¸s”Q@Žåˆg@ÔÇ9†)šœÆÉ‚†Ú{KÓžO³… ºÀ|™0É «P §dp «ªÚ™ -S¥Z"€ °@w'35ê¹99ôžê÷!E+{ð‹g`4™AX]Y¨/ªư* š™Q]ó+ì°Ϊ¦jº §É Ë§ö  aB0H ßJ Q §¾°zUp*Ð;¼ðŸÃ|¾‡]7uíz«iYvÁ "@—à£õC:ƒÉP œðœð2d@\¿€>°GÐþŠß@«ýP:5ÊùKC!‘‰¥€Xà’„WK0œ,*œÑpu Nõczaž‘FᬠÊ× Öªmº­BÀ³!@¡w ®ßº§ä( ’`Ü@Ø0… ‚»W+T–„Ê™ÙuY‡Š¿@0ÜPwpú:º@?€8@¶3ðÑðuYû0! ÿ {` €‘š‹›C=‘9R˜‚¾Ÿ“ £¸ÊÔ’.éCƒZrðêtª6 Ê”¤ù+oJ­rª­Ùª­âcvÊ Qß*®ú°¡äŠtÀ Ü Ø Õ™‡š]Éx‚ìÖnøØg–¢«þʵw P6õ.ЙPá°£nøZ Ë \€…@™$½`!°°³£J–ÒA‚‹²4ã Ÿ,™MÕ«/—WU©4˨d5IâðÉÄc(’F3Î:­ гrÊ üm*@k®¡û^lPºÒàWJ‹ z°r¢QGuùW9Y*:¾Ïð ØpãÀ»¶ÕP º 9U!ÀOÐÁ d°B? ±p  ¼ð *Ðû`M@ªÒRð@½%’è·‚«dD` ØH.+˜ð‰/ D†b9A#öyLÚâ?ùüëþ}£³˜Øê³,ºàÊ i0®Ç0I«´Ü'šn·»¢þ9µaiÁ‡1Æ7 º–ú Õ õÀ \Ào‚ /LØp Ø`°áT€ ²fÀ=¼@<©"C¡”Äp‘u¿µ’ ¼Ù²÷E WuU‚ãC>pnòškšLT,zÑ",š@‹¹?9ÌÕêìйâJ ¬Ôð­%@ F+ fgÜp¦PÁW<¥~–¢` Ÿö ÕP ƒðµãð  "ÀSDTŸOpÜp ñü2‘ §0T «pG@L ÉQ‘A¬ ·´9ï a¬±‰¢ævþc´“ÊÍu]ú rð®Šútüpˆ‚"Øb³àã¦8Ë&Ö*Òoª B@:·§Ô ñp Àࡲ`*½W°v<ò+¯5Ù,:ô.pã`Ά¬ÎAD1cÃ…Éóì©’ dP ™°¶¿Ó(‰ð= Êþ Ê(Fʨ¬‚”5’ðYœCQV(šŠW êû’ ylˆOgæ ‘1Û“iZÒ¾1³j§ÄìËÖjí sô ôà›À0 @ÓÒPïXópŒÀÓ'kd°[Àg)¹PÔÉ0 H½Îºì" ò êÚžÏT=ËWþÐgðžÐc¡*×`wÉCÊü±±Úln’£°$òjZ4ÍÅ›ÆC#ÇŒ0'Ð ì°Ðú¬-Ò¥¡FßÝ¿ Ú;ÀÒFÀ 0À úø@“ "Š®$À c%y-»bi“UgdÏ@ð ä T0‘{Á ð§À k°­íàžš8ܺP Øþ z  ŸüÕ¢,ûAc Jõ¨¨/J|d/ÇT ¾ú‰ºª .àƒ€¶¹PTD`p'°5š¿¢¦ü+Ø& Àe§oúËý@Þ~¤sú@ô ã* fÀ›ØP Ø¿«CˆHßþN“Ií™. £JÕ€»ò"¹f°Øà îàœtÞÚ/ƒ OÀ"P õÉ×` »íªbV™Y¡d1$¹Ä‹ÈÁO” "`ÍÈ­ËD4U?dï<ªº0 -C-s‰€‚°tp†ì²¿l­ÿë¿àÓ¿pº/fü˺‘¡ ’ ºà‘M %0Óåh8ÁW Z>»Sûåö]×Ì¥8  Ûy}™È˜`UÁ=À … îàÝ^çžç¥áâ€8›! [ÐÕd‘*¢€ëì–ÊðÛ,ÌR ¢0á0Ñ.«ÄséE‡…ÔÙ£]ÁBoð(€þã·ð.cì³JÀj*>d ÓzÒoJØ!Сp? ‚Ð䡸 à ¡€8g&pÈTàÍdÉ¢Å}ÇQ;µÏFý 2  Ø`"<¤ydð ^ÞÞ©CßÚ`°jš© ,Ð[ MàÂOpsgè(¶9œ–mâ™Ùဠ*0§DôcTõ\*0ŠQ€È@ ` ,—ã'P;`öÐý°­Ûºn§®¾ ¦ñ“„ §ý@ ín¬§F’í @u¡ºˆT õ^â@ìR§ˆD1 ñF@ð áÎÅfW ,þÙÎ ´0´gôGo­f °Œ [Ð\Ýá‡à§“õ¶*¸ý™ˆbX#ÙÐv8ˆx?†»¬P&-é²$€qßý(0(`h0Q0Ô€ æ€ Îp }ßAÌk²&`<ø/êê}ð­l0Ó” ù#”Òø’E]¡BgÎ ¬@"ù$æƒX1"EŠ3^´ØQcÇ|Ï^%»p§š+˜œÁT 6.!B(â HP!7nxþ ±† «¬ˆŠÃ28ßžÑ%™L´Ð¦h .à‚2Èࢦ'ÔS!–ˆ&šl²Á!‰¨¸âŠ BØÌGÊöI…œsâ›oª«¬RE¿­ºòÏ¿I&a¦RK ë?‰&)¢e¬›¯I®»ìz.Ve2ƒŽâHAÐÀ‡ 4p5g6£æWÓ F*Ë,ªÍ’•qÆÌnÄl=Êú F5}T+²HÄT á  Î¸B’°RK³ŠÓÒ£êç-DùX„ ì¸ÉŽ&WC£»ú}‰\Îâ™ZxåTx-Lòçš}šHd>ûð;D?F˜é*ƒ þ&õ¸?K/4K=EËä‰Z¨§­Q¹!¯º®ÁWæ̨Y¦'Ìp¦ˆC†±¥¦W|ðDz9̆>r€‘&ùp„JFoœøFÍDëC(N %}X[Í6r8ClTøsNê¹È¬ß¸$w‹0%‚îˆFº@‹L¸)º¼®k“ h‚jâ+–y&—fÀa*Z žqÂU„W®±3B…ˆ€ k®i"ªDŽpôªq'c®by†c"b Yd°:½Ô«ÚQ&™Ë\¨ §Q²ËîŒ "™i¢){vˆCŠx¾C8„šz(aE|ÒèŸ8ÚñQ>q<¶üþ¨o´Œ²€\ÍÔÒ`MY$éC&&õÐÃÞBàPî°˜+Kw£¦ð‘À#-ÐE8®P¦3è%p B Q#ÄIzF#t± ]dBõ-°!0ÁÃ%ÐEt$ˆ©@âøÄæ3ŸFåÇÐÇ0 ˆ„Œ@•úT!²Žpà@ذF8ê`ªáLy9{ÍÑŽ8m1=ëU¯¡EjD!5ÒÐ+dHí@VÔÚx>Eå ô =ú YP‚i°–,|€>ÔD&kªÄ¨°Q;VérûÈÝY‘jˆàÌQà•—7õÀ%ܨD8D€4,B”þXDp¤R¦-Þ€ rTâO¦˜Å>6ç£õ5!rðC"l¸(U@Á*XÙOAF·|pêSº+¢ÜZP rp£/e!æqëT±Š3‘Ù úA‡8ìLÏ A ¤!6`g(±¢ D_hQ(r0òÅQ>S›ZúŒÅ>Aø‚}èèǘØ`^¾Õ¶´`€z[¹ˆS–±ŒD ôV¸€¦\¡"È9È‘‰L€zÀD*„°Cè™è¤)°a Qd¢äXN ªÐP&9ˆXÎÑ‹«M…*޲ŠŠÙ¯xŠ™ªhS‘7œ²-hþàF>©‚™Ì$¨”‘Ù7ÁQ4rŽ“0lHMjÒ†f0­6hF(Š€†( Áiú$]ŽjôW9Î'GƒÕ\?úA4-¡ ß<á ­&‘ ;!U8&zÕ\´ª å^‘ p¡Й`°¡‹ß‰Bá@A“Œ‡T˜! h6D! ShÂâ#pð"°C}€ ª3€áOóÂþ„m¸€h8ÌF”HŽ>ð zi vêÁ Ô£"E%’ÛyèáhF5ªƒ|§_#‚* νXË0¬±ç–nb¬Š à©ê>£¢ÿéFjWUŒÈ"4 Ç)HÅ¿…`_¢ÁL?ú`‹j¥†úÐÚ̆_‰„ù¢`Ѐ±O4oüo?å3±68ky¦ ;ÜŽ'`"ÂÞ¢×¼µ‡Tì!¦4H(¢…dèâ¡õh&XÛˆà€(P ‚E€‚ (0„! ¼á›A6rüŒ@ ƒâB\e,«e&­XÂJÁ ˆ÷§<àñx0 p ;®á´~< ¢xÅ2€› ÀC=øKäõëÁV—3ôåÕpÈÔC8ÕDÈÀ¬‹i7“#Ô)Rùåɪà bÔ„€ çQÔ0ÕÛJPØc¯û+„àuWÌÛj7äk€çý™Àfm߆c‡Ú*|ØKظÂÎቈa¦Ó¨„%%‚¬‰ HÆþЀ‚pèA¾vºdÒÐbCL8C"®Q!³ƒ¸˜ã'¶`ˆƒ þ ÝTLÇdbáu ºv¹YŠ¶Ø“õÖQ w{ÊØÃUh‡-œ±³PÄu2›¡I¡¿vW ?ìônÖsoˆ¾yGÿøª *0aý+<ÀÑäí$6ZÁH S»JD˜NêœE“â%Š}‚²ÃAf`0…vÄ…× ¨@¨3›7UH&X‚˜©˜¥j²‹‘ƒ ˜IÁL!·±ðëM($þI‰˜¢°‚“±B.®ÛŒä;>ä;¾}X¾¯KAéó+ç³¹´³7J¾gI>WxT¸þˆ,2˜;n@°;׳4.¹¨eH†É±(€Ф+`“öûA¥S¹€?†Š‹ÍS´3h¨³±¦ÅK„'èB™ÈŒÑù³¨¸†F˜9p®çš (¸®HI¦¨ò#â¼Óˆ^àl¨o‰)*¾¯{–Lx»A4Aå³Á°kÄè4Ï Àç#Ÿ°;¯{D¤€³ÙÁ¼ Ú¨r?rɲŠhQ ø è?Û n€ÛP›³i9\8 9èP]t^tn`©¨ÐEy©B! UMð„Oh¢r¾Šñ‡¦Ú!! Բr1¸ 8ƒ:x y n[¹ÁÛþAš`Ĥ sdÄè€`°Á¨pD3”>I”ÍHGLÄDT0 €€/R€Þ¸;<ŒˆïÊ„pÀ&L“ˆ#x‹ 8›³™‡TPTPˆ‰ÔÅT8ÉZ{ál B-T´‘¼?,Lc`‚ h„}+½ú€ÃÔé…@€Àd .©FQ¬4’á…¨ƒT€ ¹¨€'ð¿œ2»Œ{DT@ÄELÇ`hÇudÄ\>d4y¬·¬lDFÄ0P:Pl lÈ„ k¤‹˜\€6"¨‡JȘ@.<ñ‚;o!¯)<›Èj=,{!l˜;ÉI]L |‹‹aÄÂ+Tþ”ă^¸Í{É«i‚g´Š¬`" ²qI&DÚ.ñ3.ácø„¸¨Âq”£|{G} TÀÄtŒÍ`XÇÙt…pÇ}è4Ct¾èsDªäÊäC…E#  R¹Mh¤±x†`Žz€‡ix…鼃e8%9ð›U¼†',aÜ '9ðlR ̹K‚iï|‹?Y:|c“Œ ûÛ‹†ú05ðëP°v °gœÉšô¡ë®<85¨ƒk  ÿ#Jpô3¨Ð§ÍhJwŒMs”ÊvNx$¬Äʳ³J­ÊªtTàǰ KWÌrX¤‚J Ê„‡BÈþN˜—OH´t´÷÷(º½(òÆšÐBCLEÂĤO»˜‡F`O˜…  ¿8¹ Ò¡L8ŒÆ¥OA$OÁ²k ¢%ðÛ ÃI»9¢Dùp… PÙlǨ4GyH¾}˜S }Áß\S¤S®dAë3 …hH,]ÐX8çX¬„U¡þÑ‚qèkS“ ÈQA²ÊˆQ;¡šÄL˜2 U*Ü ûƒ¼Oh€TS8‡u0ë˜ þ”̨øÏGÙ!e²ÃμªËI,Ù¬øx÷„åÐ7ÑäkÓä»Íä»P¦4 0À p…`È ¥V:• %ãÔ<7àþ´AMüJ0 Q6¹]ÈæX…B¨ ñêHœ‡W¨†B ˃=2)jAâ« æ»ÊcÁš'È˽°»p@Õy0†E?ð„^H…DpÉþL–˜+Í9wȆ|À=‘²ìº”© ªê°³È…A¸ ƒ30œk» õ«±‹Š@… ¥Ö¨ŒÓ`W0ƒ  `Êš¥ÊÝlÃmÍÊÛÜÍo¥VžÝÙ~Œ;2X…dX…Qã„È6ñ"ƒS¨*€‡Bp^Kõ3ù Ì¨È&ØÊ<[+µ-ØUP…¶[Òà –­TH‰œ‡$0UÕ„YÀOðƒ< 9þ”7þ%ƒÃ8T…¬0€ø*°†%ÇE¡Û’±x*˜†äHzéÑÍJãPפ€ ÅÙ¨|Ö=ƒ¦üÙ|Tº`˜ÓØ$ŸÜÊ&ÈVWÈ]¤mD ðJ¯4Š]Nh´?aÏíØ6ÁZè?n†=ø`•V‰ù À…ÐÞÑ:ØÑú^»½[¼‰Ü[cøZhSÈ9è…sðkÀ<‡^0…$ø0ô ÌБYµ¹Ê¼w¨Ðrp‡%°†"“ƒ¶ióÕ|ȸ€dˆZ©=…SÈŽ  ¢<ùðàG¤&@Ô}Mœ¥ÖXZ ˜Yh°}DfMþ¾ÜÍVnÍÊÜåÝœá&˜Ó9}EÛY¡0Ñ+Ð$  0¨?iHñ:El؇¸†Éë F˜bQZSX&0&`PÐMȃac1†^(ã^˜4ö5Ž_kkhcq˜…s˜…^ÈSø…'š‰ܧæÛЩ ÕÆ‰hÈ€s(ä¦.ð$] ‚jøÉ.‘Õ®˜ Æ` ކ¬Zœ`™qHEÙKðà2ܦD]8=åžíYTx€ËÇûJx€ä££Ø]–ÇeÍ¶å †¸`]óèG68.x€"6f  n…zb¨PWxwx]è…Wx^p9þ~lžn~36c9ã<ȃ,FE 4HQ@ƒ_øH.H[ [ËÊmÌÿµ€s`r7–5PƒuX· ZÜ8‡6¶Ü"*‡UˆèJ8…HxE2¨„d€‡ Ð…WèhƒéèŽÖ4:%@9QnK˜Ùœ=aÔõÙ||V»äÇqUá 8hJk%]ÜξM¦ÄÖÕ> óÎ`¨Ÿ]ad.f0Ø2¸-.GCù“+(bª®þÒþûdÊ´ (@ÅÃC8KeMª€yƒ±óÍ*]%£UÕY]p‡VàwPƒYȃ1½^‡_pk`q9ЄþEÂ-¨‡ˆ–ÚÁÉ)]h-hƒ¹rx¨‡R—™Ê„éÉ¡Q.8êi í›JŸÙ|deâWñ$]ÜA¯Ói]fAÆá<¦L娀ÖA èÒöYRÐí ¸2°œO– “>Ñmîæ.Ê'ðàåÞÖV“6V²]î´[´‹“ð&Ÿ&È Ò¡˜|–Fx9°wp‡^ÀCЄ:(Q@kfx9 ’"”J>…B¨„qÐ-„Ȇ‡R«8øÁ3p .8—¨pÈhr˜†ÈNnmSžÖ›ýÙÎdž;¥+ñ…2À„[VS\fþM^ÎMW˜ÙÖ-fí£v$mR8êÏîíã~^>ævn榠ß]  Lèéþ`“޾DÛ<+¤yQPš¼ä¦ Ókk™T Ø¡Èk8‡!ÈÇl‡«„W…ap‡W`„`­è0€‡ˆ>8Ì¡‚Ç&œ cà†ÙÊ×f ;L2Ä„=ð¤Lhì;Ÿýpl †¦Ìm×Uâ¬?, =€Pç8Àm©DéL]Ó¶eî¦$a£fÝë †}øðÒFê= ƒ#°Ê'5 (l@_®2^PÌ :‚Pvê^îêŽ ø Q®:í`þ;&ïT³¶Ýþ5ï‹UlhM`owȃ`€ãm5<øWøÚ@ /ÉsN “ÈiJðEÕTP4\¸Á"=Ê8/6=ƒShÔ xÈYíœ}uÔ®¿êÁ#‚¸øúA õT']]õ5•‡KQ‡‡ue·ÍàÆu0à†U‡Ÿ~Ç#àk«7c˜Ë憸þ“Kpbgÿùgßî±å¢ë'—¼ îiŸ7zäRoÁîPÀwh„Ò,„:¨„É ‚0€%8‡ [X…JÀZ]¨ß©Z¨„=€2ñ´»] ÃHÈ^vH‚°jÓ}  k×=þJ°tÒ†øi%NT¨?4x_ø‚ð#_xüÇY@`‡­œULeõTÑ‘/e õàÛÌYÖ¥å¥.„€ƒ#ùèW<ÛX×#&ƒH8…‰^è?·`nÝdreï}æ&ÝJ*ø‚Ýëk‡j{Žú°X‹ s9Ïq‚a€EØb‡cˆÉmk¨FhäWÈóBÈ*x†=`€=¨ð`8OH\X{©„œ4ˆ€'ˆO€ƒ³ñÊüA€ÑDÈ“'¨ÀP L¡BTÁ‚¹ † ;8².b”åK£F_=NÀòDȾ’&O¢,骉«}-]²DEa¢«š6þ÷ÉÙ¡CÂ`¥àêH“}E]uQ¡B Žp»óH̳Gƒd€P ®jº˜öP˜sì‘G‚•lb餥JäP¨‘³ˆL´B:ÒCåI²D?ˆ°Å¨¿Â‡T]“c@‹&qƒÄdX\\qDK Î-DœZÅ-™ *^ƒ×"“–jZp°x£ ŧHP¨‰Jhꉺ²ï‰ =·mW WIà>’.QE„øP¨+èXP|ù’ñâÆ…ÿ" —*ç)O¾|i}õö6kšléŠÂL ƒõ{²C`Ì®2@d‘cxÃ<£Ã-òWT°þS õ‡ßX=TÂ&¢Ãº¼rÇ+É@@ 6ð¼O!=À¸ÔC9át„+OàA"[4QXaªâˆ;0&Ž&îœÓËCðò‹("Ô³Dk3àÐÙ w´ð È0Š2à Zd"B%…0F%§@p˜Ô×!ܲfáD 18AÅBˆsÜX#Çrñ@ôw„%îð“GI–$“E1¥è À Å3\àþgõ`s…¹Wpñ”NMÌcÆ' ¨ð„…9ÒË TC¦8Ö,‘‹ZPÙB58Bb ºœ6ÍiŒ“ Ãð$S ®Rp7«¬ Æ`€'*!Ô½‰6\ìƒ ÆURO=$&ÏB 9T*B`ñ†$‹Fá(+ù,QP2ÁQ€Â•Æ¡J"&™·’Ô|±Tµ|ÕAgj¨êÁtzO¸b‰YÀ‹­¥x‘Å#^Ä „Ûjƒˆ €ø)Š(«’.)§ ã á‰*’B1|ðáÄ ˆl›Ë®ˆÜˆ wë2ÃãˆB‡$óI!ì±Ï¼þ<™8þÜú8õ0<Žìã$#B2·ãîç*¢$³J8|+ÄE!Ü`SÉ*ÇCÀqǨ`2ÑDZƒ Ø„óû-aR|ËÀ©¦@5L÷u(…ù‹>ªÐ¬œo> Q @ ‹ÚÐéIæíÓA|,ñåŠ<<¹G>&)Ѝ\?“ÃYWÅR"A1¨-l#À#l9'8N@P˜.2±7ÜCܨHÁ‰¥äç†8ƒI*qoØÊ¥xºP –@V²@€¶"]¿˜GÔâ, !ñ\àFŸvw¼Þïw«8«hÅSì©à 7Œ7Å)RÉû *à<Äyö!Ô|þ\r†JÀAo ‡*A‚ùÈÄ&B˜5Þg>I<êQ”:ßÎÚ‡6 CæPÔN¥«ÁD%YƒÏÔPb@ôÄ'ò8+@†ZI°mÔ†7¼¡ €¸€Þ0„#T˜› a·q é\Z &\ò„V‘a¥¸Õ´  b@NàÃ0ÑQ \yá(†nÇCX‚=ð°I0dÀÆ)ÆINnœ‚œW$;Ið¦ô§['¨‰r’AyAq;&ÒOWôÓ(Mè@D:P—"¢¨ üaê¸Bä#_Ñ÷(GµÏ}E à\“ŸZ‰þFþÚ5=zJT)HZÎ@pèJpBÚ~8üaÞ¨!:¬° rü¡ø²‹åÃ@Ø€ ~Átq]{i·äB ”Â2ÐÄ/†QjB0”a)º  æÊm¨F8a.UHÁà–• ØUNe¬Pò*“…<à ¡ ›D0q²“ týÉ]Õˆ L°#KOH}Ù¡z8ŠÍ¿(P~åû# )A´Œ’zˆÃª´ …-±š)É—ÆGk*AKD®°Š1ˆÁZÞcÁ:Pp Ä`d Ç r¡|@T¨† €@Bx©ÌÈÅ8žºþ”ºÖ¤ !ÈÏB’1 Ü!â…Ú•ÂS¹€×+Ô$`¸Bz 3N\ÀãøÅ.òÐ âj2ÔÆ t+'B„¢àBå:a|n¸Z§7LiþJC€>¤OvB€®@Q•B$2£l¯rZHð†âœ¡ˆz„Cüdh6¤À¼²=ÁØ´L%8ËŠˆB!0@´#BøÍÂ,¸¤.äã#Bœ<€Á=ÝS%‚Ó%Ž DÂDÞSm\çÕC Œœ€ÏCTœuÀ!àžþˆ$R¼ÜCì[Èà‡þ¬$×äœ@G±ïñÏ_ðM íLÑ%ÍÑýØ9݈]MI<²-á2ºKîƒL.ÂÑ)‡`åŒx£Úy#|þ[ €ã8–c.ŒÁÜ ¼@>TÀ+¼B%À™=A²¬d%ÀC8ô€%p<ˆ#(0B6dìàÁ,.üø@$*d9U‘(T.‰à$Z¨qpÁB¸tdÍ'BÄÐÑÿ¸â‘§Mè锄³ðÝjšD?à ‚ ¼E¹XnÑØ-APzÊóe’YJ<ÍÓ,c$ŠC¯ñS.üàÀ˜­V®v¦¸½Ÿû¹_.Ü È@& -ÌS¸‚‰EBqƒ%XÀ5Á]š68˜BD#Xð ¸-/þÀéd H˜€B&,C2š<ÚMœ€=@¦q€qÔU%´t IÔˆ‚J¾T‚JfJŽ‹þ¼Q¸Âíƒ%‚[TKæ.„m 5Ô$ùÔ¤ü$ÍéL/ÆÏÑ‘ÀÒ [e Ш4Ár–D"•®š` è ¨Àì…„Ã ¢ ¸€uâ@uÎÀ àÀsÁ ¸Žûqå (€AcˆCЂ ì7ÀG/$ƒÔ%7 CY€B&8°èçøÁ"ìÁ/èé\ÁjÔS=ˆ@çíN%AĬ6` • \@þçµÀ@X5ä7„À¼4 |®ºÂÜ&à^jø+ÀÁ8BM A2Ü^¼øC¸Ú>ˆÂ î™D"$‚ÒaÈbææ‹ÁXÈ/:Ê¥ÈØ‹±Á8i9’°5$.˜\]i–¢ÄÔGœÁAQ|HzzH¡B˜…ÀA¼‚œCkTÃ2TÃ,Ãk¬LA6ô6–nÂ*ÀÂþ€ àˆƒHAäÁ/° ô’s8G\C’¤  9üK†ƒ.€q#ÄOÚLбL”į̈ï{´Ü‘½„C%›•öC>2ÐbïinÖb©Ö"ÒSŽ˜îC*L† @Aà@! èkJDÀÔåPXBœsþŠíCÌ9Ì‚˜,ÃüÁ2ˆÃø#L4Â"€Â+á /ƒàšªð+ˆƒ A+Ì&ÄE° ʤ $Á!4A!ƒÌâ9 #4,B#`B]CœN˜ &üßTå½)Eƒ©@¦­‰q`C%J˜çiLÇÔÇD¨œŸ/Rļ+8ÔN”„< $åI çÓ(€,2-î\×f¤Aøžrm¶C?¨Â``’3S qœ0´B+ìÁ! €)ðë‡$epA>dÂ!T€Q<õ… @¬7Ì‚&TÂ!\&\ð>Ô&Pð>„@%œƒáµ@ øÁ+à9,;àA Ђ,Ã+ˆ9ÔC¼ÂW!"zWÃKôB#Ète‘„%4#4‚*Á!˜‚8þœÃ$‚9ÏËýDaØ8‹³ðu©„(F¢@L…Å]íÄC\éIÈ‹qâëq¦…lcAjÓäÎÕfAm‚vh‡¶ A(ðž¬Aì.ôC?øC_xq$0ô‚&|&0zIŸÄ!DB>TÃ!ôÒ>0s\Oö‡%¸ƒ)¼Á9¨å,´(XÑ Ã"ˆ#<ƒÞE‰³d›ä9ˆC¸$ø>è^’ét9”óp8Ȥ-|Èo‹€¼„@D@< ƒÆgˆ§DIyŠMdMH• Chz©=ÀßÂê훂géèœþ7˜ôq^ö‚sC]ú Ô&-ò >Œ¶Î¥AMê\G…B(Ì$2˜ƒ9P2ì€ ôÃlã„d÷4Â,zICŠÅôr‚fBŒO7ÁlEÌ:!ƒC­S#ãîßBm~vEÿz´§Øþn—¢Á"hBD"ô0øÃDD@ –E^ìtñë8ûCmøA=È9’Ày=ˆƒ¸Ã¸·€5X-`C¾h÷¿èý¿¸ƒ80Á<4ç8 lÖm7ôB‚èB%ôXÀ<¤&,-8÷5èA F£ßuI0„ø„zne8JB„…[zÚâ²dD þ¨Å…„ƒ<€b«LÕIøC8À?¸JR,îË?MíM¨¯#’ÂAø<>à88€ÃÿÒ‡ „‹ÇÁgƒCè2tÐA?¤DAD}# A¤00!$BôZе L©÷’Caþ0ô>C ‚ôÂ+Ĭsâ4éúqçG½jZZUª·Lœ8*Z´P™¨¥…;q¦À#âI8…šì3©ª‘;U‡¸iZd˜ª#pPÌ;ô©ŠTPJšLÔÄ_P¡ûzP0jô…#&÷¹r… ÕQ©œBuEáAÖ3¨ö•lâ+0\²>C ) 0X) Öa_°žL»ÂqդǾ#OLI´ï/Q|ˆ!‡ dl *‚/ 8ÉúÀ±¡Àq¨PÍNàkGŸ à:)â —º&·4ZÔ¨A"CIÚ K•ªL«™îîBÅ>ûΜ ”„ =~˜ÈÑ5+b‹W"pˆÉþ'#Y&lÉ~ü°dÉ‹Å;רÕ0!ÎìÃä»ë><1]á…Ç“ªpBú0Å«‰-xIe ÀºJ¨ š8Ä-·°r…©§ ¢“¬Ø2 ª ËÊ >“\©àŠ ( …N°²°­‚iË)—â­‰3N/¦þºÑŸBÆyfšôhl6iÌ3|$'2}ôaÍà|âhL4Ñ$褄*èèÇFÀIeC XÄÚf9BÂÑã®Õšx‚/“J*î¸7U€#ü€GwÞXb e2y…€|òIf•q6xŠ Ö ‚Šj.ÔS~B®`ï !T{Ÿ$ð`-•<þº™‡§+êY¤(Hh˜}dJį®ô§‰à 8à€€ª’ž¢ ª²Úb+ª 74+º>4j•;ø à7H1–4ÈhBÞ˜:"‡7P Ñ'¿jýJ—DA‹"Р™!)ÒHAÀ‘Éy5KãÇ+_ $p¦„fš±'°`ajÀƒ ^Ú€¤<"@žÕâ$ªY¦BÀ¤‰7‹“ZÈ#¨°F‹j\ÈD†1òÙ …g^h!ˆr‚¨ÒjÂt#&X‡—zàK¤ýabUr5¤•š ¡C"@£‘\­c‹ZÿBP¨DZé²ýPo®O¬ànVÁ)þb‹Í Œ¬P™Ë• B 1`!–|¦ †íDȯºõ–©&ŒùccŸš¸qŸC¸Èä#,cŒÈ(ÄG#§ÉPž eÊ"ì]‚li&5Õ$¿¦ <CE†¢6æáBãÕ:fÊöÎuHød˜4Q¹"*\X†˜ÉÅ-<)Ç€ ‚X†çðððÃ`Ôˆ”= 9g–Föé´ æÍ°¤‰VÄ)—-B楦›Ðh%ù‘_´ý¤‚ ©˜ Áý5ÅÁH . ƒ<¢Z@…SžàŠ\¡n®À„옆 ˆa c(†œ pp> þ8…7‘{ßz&çZý°qÀ;Np‚8 cJŸñœÀ˜(|JP2 B'°„Â6臧貅kÔ 5PÂF)@¢ãÖhÌi=O8<]´À"-«Fw^¡‹è1â`„ÉGÁK0„)²ÁˆVÀå(Ç"rÀ—&$!qSF9@±…-`B!’°…O¨`r^³Õ­¶àc (fè… Ô”­bYxD)J1­ ô†`Â0f1‹<,ü Œ^ñ o”¢ Õ Šñ 0„`ƒ¨PÁ…°8Ÿ˜$r!ãÍ2 d\ì¡@¢ ¦D/Ö5þP,“žˆN0±%؆ ØÑÕ$Bv^¬"F 2†¡C@ã0bÓ%º¼©¿QÈšÀ=ì ºxµð *(À{Ä>`‡˜àƒ „!½·5XÃåÄ:|ð‹ ¸CH0‘ƒ}Øo \ëÊ ш'l(Pnd ýݪ'! Oe3r¹‚7 @1 ºPÁÊá‰uàaÈÌÎмèBƒ@D ¬qr(€\x6{` z“œãü&9Ó„\å¸E¼âÐØ8xùéžEg˜†uWÜŒ ìñO!t¦TH‹€£þ ­A®QK 2.x†5ŽôÀêµ "x¬Æ2"5ƒ)Dã¤#-#¸§3—.až˜ 4áA2a‰èÔŸp¸ƒ ¸FI>â3ˆ`0¬› PKÜj8=(Kr0y¨‚)hÁ´Ñt B@@Ä80ш$aƘ‡š „ÔÒ$–ÀÆ ¡?ÔÀXÇ"žÐ–\¡hŠ`aûCsQÎc‰hC9lqÄu>ö1ïÄ×êLŠÔ3JXÚ,;rЀÞX¦œXi E¬¶ Š0Æ5ª1ÀaNí9D Q üáŽã±Èp0…lb,0€–‹«³%àáþ~˜B9ÄaŒ%d  ؇jrüž&pëèÈø8 !‡x‚!à0—®¿è‡BN€WÈU*JâSW¼ƒp0âÇp¡{ÝHš§e¡õxø1qÌ"pØt:ð‡ìÆ›«1åh]+º„` tPÇ=!!Ñs%°"èŠô˜Øâ²Ég(¶Ñ ,ø“‹[ììÌPƒ @ ×FÀWul„r’ÓÆB¦CÙ†@(` ¢\ wSÄ80Á¼ S.Á¬KPC/ø1 ÔÒ™‡I<ÛÖ&èByø„Ÿ›€ 8´¢­qòÊ!*P TªMþ04¢+ð¦…{È=TÀA¬ácöÂ8Ô`0Z´ÁDÔû؃&<1Ó%ÄjƒOèÁþë#0沑%r@8Ä‹±N¿zèŽÔ¤(M IE¶f fƒ>pÉ'ž²‡=®‘€6ŒCA¶Ü»0”r5ܨ@&2Qgè¡­Ü$>\Aôô>@ þ`!Zf f€J*L€XàX ÎJL JO’ Da/ÖŒ)H@5h¡¢æNâƒ5,¡+0^¯® ¸ ãT ᛜ$* LA žÀ,,$÷ BƒxÔ( *€ B ±‰ƒä¢ùËÃ^Ë覯 ’.€à¥1ò©X‡tLã1! ÌA3–m³„€<Ç:kýÜOì´íÚÔ€† Èáå¬äþ¡2 †ãcX)ž ãT@zààá ’`~À"Z@‚À¬,¢áÊ> ¸HÎL LD ŽàüjÍC@†˜€fÁxÃc7,¡ÈÀ !H®àôÒ«n®€qž {Àz`øN ’å0*"Šå®"( ¯EžDÁøªð[hMúv.tˆú4G1â…1(k £D2B§˜. ¢` 5‹Ÿú ¨J¶¨ÖÏè0þ jþh@ j@ ¬Á"`)äÂáà!ôê.üLNzÀ(*@D ^à¤C á°ÌвáÊ!<Ö!þ¦ ê@ÌËô&œF¨ €Á¦  ò@H€æd(.à€à* 3î® = d™Z.÷‚ NDƒ2äUäX(à 6èC‚Õt) ú>lúüÀä³+¸°á7À ºÀ ŠADÓ ão6ˆ: *¬bE’BnP*„^;ÅK#¤AœÂøäÂÞvE燈Ž`)àO¹òk³ Äq µ1$öHär+C–„(aB/±@5r ž ®ÁƤM0é@­ ÛÀB¥ ¡:@Áúì¸ äÀBŽJÖLÂ@fÁHàf7­Î`ö`xÔ@aþtád2^dú„@öa4á ®áU#çc,Áºø£È༠h¡”€\oœ:èfÉ©m) /*@*¥²›àDãÂ-zN;BÈôà+@Ž.V>Amø  "aòA @…>àúƒ“h^UF(C27Hl€³|*F"à Ìà30Í Ân†€´*T†%4ÂÁ,ÁWšÓ²áBMÝæ /öÂíš à!Yÿ”~)áá2¡@­m¤ æŒ!†×[,)°èçÐa œ€äÀ¡ €z ãØƒ@"ˆ÷ *zþ@2=ÑØ!ç \:e)〹²å\þ•ð´\ŠÎù±0¡VÁ:¼`ø`>`Nû"W:¡U4JY2è!s)Á°À•y¸áÎ R#ú!G6fAìÄ® 3ÛF ÔJBà`8Á– *œJT }@âw)0 Dá®`ø„MÑW°x¸+ž B@AK"°Øã¼ H€ Ü JAZ  k>sÐà÷cè2+C`Èù2dŽÙ¡ ÙY hNä`åA†šå¯¬pú$2É oœàáþÖPþ›âÀƒ×Q.)·Q3—& vÀjéT 0aýXX0/áýzlvaþúQÄ!N£$* ²áަq’#dL¡@$Ïí>³2á1$¿y°ÊI$Àz¡|Àªô Xô ¬ œ d @a Žàµ´H¡AÃòç˜ ÐÀƒü8CœqŽŸ‚Ÿíµ*"ˆE@þ pÛ4O'ºÜ7ŠA‚ @R€qÅ€®o?— 4 4H‡Qƒ4Uèá2&ÀÔ XPf™¤­…# ì²m´¤`La@A ¥K‰9õ~!öàh^¤¢øƒîÈMþ˜@œtn¨+ ~€ ŽÀíàdNÃ1?l ž Dà\¢ã¾øgaY¯ ŠÁ ´ÁêÁ aL¡ü ®½Ü 1¤/+¹Aƒ*ü8ýøx𦛺)‚Tä>à¶‘{¶t2¯`òán`R 6üráNàaÙ’ä¥1J|b?˜ ¨!ôÁ@Za»~ÂöÊ ìÁt9õý,T FÀR†k À­áhê ~ÁQùòDV‰'ÝbÑxû• Èá–"Óø÷=¶+®` ~¡É–)rÂá žâyÈ}@ä   èmMþÂ1¡Vƒ®Ó ºù9Àܑχ„œÁ¯:Dz€PÀÁ8»#\›¹a ž ® Öáðˆà@™-=›¨D4`u&VIR{XÛ{‚0Á ØÁÆe¤@ì ·c8†A!0–•¹ ˜Á†/N¤ ’@>š‚Ü[(9p€ ,]Л¯û‘ýB| BÄ«'È©¸à6¯@ŽàÀ ´á æA!®ÁxT‚€èœBæÕÖž`›=ÐÀN?¦Ïó·À£ö.œ‚†°AzÃb ½!àa‚@ºA†A>Jà<þ”±OØIÔíʼn*÷ƒKŠàø00>F<×t÷QÄÎuo[ ¤@ Úg Hô:Ž `ä T€™Áé8¾+CÞ nUÉ_òàÁž`)})B°K(ÇD€ | à Å à2Wἀ« à ~á>¡¾S/  ᨖ ñÝ…€>@|Ï%¤Ã+nh¯Ná8Þ vR€›Ã±a ²À œà8à À´A®pÖø‰È?=xušHIb?å_É­ØÃ S¶@v wG †@ ä gáäþ°á ,šcÁŽ„¬·+*.n¤ Ûõ2©£¶ûÈÁÈÅèè¬a€!¶ÀõÀq¯BÀù˽ۺyä~aL’ î¡*†å=® žìK´OˆATBB¸Bñ&ÄT! ¢šˆé˜g\íÛ‚‰„&(>hrΓ'®R¦¸¯eK‚GºœùÄQ°ùJé$dMÜ’l8nh+åÊÌ![GC6œ‚‡OÕ©ôiЧYœMîkBBE,öÒ é×ÏL’j¨QÓFŠS­>©VÏ•#ØY¸¥–,›8Úg‰`“od^ áþR ¥ 32JDNX‚‰ÅKÐß«•:ÒãÈá™cI¨pj,>ˆ21ùÅË#PG~ͪC+‚¿ãÈ[VxðàÊ•'[Ž„eÇ.u!OBP~ÈN;;æÌÁœ«JÓŸ±o–©Ø§ÑÕC”,aÏ-ß5GœÆd‹1d! €xqà (Ä!ÀRlx%HT[ÅNTXD'€£†lØrþ´DÖO¤B‚=Ùc. ‰) 4ò‹Ÿ@QG%\ÌtF0ûpñI xôÀ=ÔGZŸäqMX.ÑÇ^Ü\EK[„øÒh¢eÙ„% A‚%`@pÊ)ÀBŽ„þD¥ð!(‹ãŽšDH­øð‹qÈùVpÁÜEnqÆB`GB ÑÈchÀ±d(ôp‘Eâa2Ö0o‚ ()¤JT_–°=1^×óÂ#YðÈ#¹<òê 7Œ1Æ )ÁÄ J1GSà`¨ øt28r2Î,L-ù ¼ñ‡û`¡ $bL[” …*UðG=M4!Cû`âÈÑ8ÂeηOL1YòÄŸladK‡¼Ö$iXŠUmWB7ØpSf©ŒÂÅ*wdᄯ˜bH¦0"̳EÆüòIŸÇí¨Eœ\±?$Ìþ‚‰?h°€‰*üñ o<öƒ.Ë=ÀI˜˜°CCB¸"Ä>ð©40l2Ñ”c"¿äóÌ 3d“Í `ƒË 8”]v RƒLƒ>ˆa'Eà•Uà<˜!8qKˆîž‚1h ƒ†@O·ëOJnšKPp&! áF!0àЖï@G\CÚFŽ AXLN]õ•œ])"ÃdœRÒ±Ç*ô`É)€°±õä1-A¬ÃË,üÄ2L+¼ìÉòŸáRfz €¨o°³ƒGÞÔzpÆÑaBPAˆt’ÓòQ ÚÁ§W–DTcÀKtÙØÁ‚HdO>Hþ ‚N° ¦â€E8 UŠ0¡©H Cw„3p1)L¨@˜HËÖW-=,bqBpŒ»"›QUŽDàE*‘/Ð<ƒMèÁ00©Áæ3b)Kzp†‡qA3yZK0QˆBdl N(4‘PÁ­`Àˆ0‰ 0ËBT‹\dRŒ‚ÓBÀާiÇ|a<†‚˜Ï=*ш+Ôq®}MŒ –`k(âŠ@À1º1Häaøß3Xp‚5P£A^9Ö±ˆ,VEèD…&d‹v ê Mð“?çí¸Ë ‘ˆÌ׃p#¾b€óŽp¥è8i ŽÈþC*ÂRGWŒ’&Èa(ã’&9*“5GWȃ•@„Ær“`ìAƒ#LÁgÄb  à- °<—9§=€ÈØ‘„œ$!‰§v&w)öä“6<É|°”0#E€XÂ2ª!Ž]@bèF𤠠P¼b¹ø@#„ŒI "“²0ÉÑ áø –ª4uª†e2FŠá™ž ‚e ÁÀW‘ô%“°È†°±„%ŽÀSùd§tOP)€‰+øjâÐ0¸a äˆQi:p¹˜Ä$Öa q’sy˜kX‚Š”°Ã='9+] ”°ÓiI+þÅ`³’™R펜SåLÐi€|Tc€]F ‘h v`ÃÁ(~ˆE¬a)Ô–Ý d àãB¬&C±34ÁŒg L»lˆ<¶„5 †.ê„Iðâ \°ëÁ^²&Ìã°9B8^ ÜÊg”:ìÀ GS™ªiìiÏ‚Ñ 9˜¢¦0#~QT@“`#Œ…=|9aù” Î@Þ¶²£­ëœˆ+ØÙV8ÞÓ )Iê\eÇD‘ÖŽCŒO,fŠgäâU/È…€_`¶²ý?pÁ„ µ9ÈnÊÊP'Q¡LjVÎØD*^ n„}ò æL,ÁKˆ¢«È7þ´@9\¡› ª^R`œ® Ø G=¸a¥ùìRKÕÓÚ3×ø@# À„ôØòS4 ZdÙÇKÞ+œ¨8kÓäš\Ù9-%ÉEkvÎWª9¶ÄÇòqRpnpAÙX†.^1WèâÏÐ9ÈqLÃâø•R„·8¸M™Ԁ…5[g„Â.ÑÈ0‘„$|f4q†Í!®@§1 \¸6@eêâ«I‹“I" `ˆEŒÎ%–(7ÂQˆ3ð´Lµ!OL“ôµˆgWê0>ºcÊ܇(d‚Aè{àE–ûô4T3 Ü8ÂþŠ rOäÜm-+DØš‡À%Aœk6c#±"ЂŸÿÌï?¿âß{~ÅÞ0QÚí¦&^é[؃I¡Äü!€y¨BÖ Ë8c,‘‡j¨€:›Ž­ þG"Ì W€]T‘&$B`3a0`.“#øC"à¯{cùÐØõiÅ\Qn AhðÁÄaOç´‡(Ä(±Z `ÛÇiB¹ä¤ Zü¢{W07ºãèò}CF3blˆÇÔ ¬d(Ä A xØ}v¯G=D ‚½£ØHE‘! AÈÂpKVÂ/[‚"Ü"¥ï>ú1‹a\œ–xuÒÌ*`þ@ÐâX0;ì|‡ÿå£äÀéXŒ‘¸™4Áóí¾ Ä Ktà d ÀÔ~ túÒW#Ô¡¼Vz$G p • Z Ð×s"‚´€J¥c «  Ø0ƒ,´S<âs¬ñ~=€fAÖÁpg (À‡0^ ÀŒ óðK‡° þ¯`‡À=€ÕLÒ¡ W@ †` ^W 3^* )‘äã{n–~˜%1ÁAõq\P?0†N­!S­”ì,Âr@faUx%pYøà Ô¶Vk­Ði¡³`*ˆ*‰pzð ½°à X€(ìP…p¦÷? à’ãŸð 7„'VíÒ.–pðÐËðTð ðP–0‡"Òû :lh Ю@†'hP ŒQ$ A`³àKò[€ PpŽJÇA}¾USMP @ 2âßW\–4çƒpåfg¨†xÕ jFòG@þ€À[öS:cOàŠòXKl !E°Q–7²p†h à ³ÐL0 ë0ö€ À`Û8ò8ØK >°Z›– dpb¹@¦`ƒcC±UTQ=P ³ å° `ðÕ€ –ÐÀ  è¯ ØÐò RIè$•Á39R$»ö}Ô ÕXZ—CTH}"VLÆ ¦àšÐ á zÐk_c>û@-uy—‘øT-¿DSü2¦5P ùÐ’w @•@ÖΈ ì€ q°Ù6‚@! yYq“I@€·€ ‹ÐLþÐm0 ¸°"ó`ìƒy3S/ îP¼ —˜ B"àù ™ j@ Ž ö85:õ~– ZÀAà¾Ñ?ðZ 8P Ë%\œ@Á%÷?80´i”\@‘  ƒP øc\ ½| pk÷Õ'Þ8Ñ"#j ­ð Ø@!œó0 † f¸I í0©p ¥É"I 0z TóÖ‘0·~Œ¡ b€JpÕpny ¢0^c¥p@X€‘Ù lPx•)qƒ™UÁÎP¡p ý` "Ãåpf` €(`%cá*h-ä[u€ þER&Sð@ jPLÀ=%lÀö~ápç€T°TÐ AP Õ@8 bæYÁÀáð ù€€€D0 € õÀ œYÿ@•øRo ]ð}éz7–ª búôh© jY´P ¼@^$p †àL°M`†pIp'` ¡J¸ž@¾³ @ê.©’š“¸[n¨ ° ƒpw ¯ð€ g ¢e¢0í 'Àp㢖YEÐxÑŠ5šI0 /…v [°SÐþð4‡Àp°ÃÖO°S• …Às[ …0þ¹pRÐC@ ¥¤ÅSÐ r°“â å`g:PÕ ¹¨ƒï7ù>P«€›"ð 8@n@°P N «€/Ðî€ c‘OÁÈñžbT›v …Å  ˆh%á ñ4‰yh [Y&PW@…P A ÷zP«À;@ V ¥Þ0@" K  ¿°wU5M 3¨¨P°è*—{  i©¼"¼ Ÿ *Ð"LP œ:ÀÐi ê³I€ ö` ž  “ðÒØˆB9ò¡ 'yÐ í\[°“ Ö°xÐe„Nóe!E€ pÀ6Zq,‚%  \Î7ÑjˆíP8–³Œ5`M@-ÁKÕ•OЉÐ9Ðop{, »½Æ°©0 A'A^¿5_Ÿ±hûPn‰CÅtÂrPP9Š\-X`hPxkp@ZÑ „­ œI L€ÎÐIÅD¬† !¢9pùæ…PÃË)qì@XpËE ãÀwÕ 3ô ì*b€‰yš7g Ã0/‹Ö›+ç0â0 [½ÜÀ Ð: wxñ ­À œð±R J0Ï:á:0áÀ ÐŒWf `Ü'PrÀKð&nþ¼–”1ØP…€ð@„Oó ?kÚÆÐí°¤½‹BR¿UL?Õ˜ “áóà>g PP0CgˆBhYÉú 7.ŠL€ <£  t@-˜ÇB°OP‡PÕ  L "ܼl†¢ËÀðp#¹r@­#¿k$‡0/ëhý²- îàî0 ç0 Ö {' Øp•pØ@¸dP É ±âµp£c0 \ 1è:5í ©à[CÚ' 0 ±P˜Ð Ê‹¹™pŸ‰½zÐu Cx‘cÑ?ªz0ó -'Ps Í–À þð 5O`g$–}ë”AIà:4lü:0ÉVl€lPÜŽæ‡7ƒ8ˆÑúÀ¶ÝûBa±ìð r :@ö$(Þ6€TmºÐ1`  I0 VÊ Œ¦°„Ñ,Í5u¹Ø|Z°Ö`ÍR°Ìq}{z' -À CÂn`¥ÏÞp[Øc° {ð‹M:""½/AÕwÇátË “@ €â®©­€¼P †Pºˆ åê–' ¶}l uà=-¡E†tvu! ‹PÓ ©p ˜p ½àÏûâòÀS­AZì@س6' Y• 7¼åÊ]þi†hˆ¸ ‚.‘, MP  º z(½,ì Õ'€g -ÀSÜ t Š ™ …Pžjõ‘k$©ú-žÛà¼ÖCàß «Pã°bº@känpñìw¹P cP wp v6—Ø.Nl\@Laîªp  ` u` ˜M]¿Àk¼Ð¿pë}ùÜÇ{ì³;°' ëPr 5ûR*®ÑNîä\ò|< ³\ö÷6l.±Øû’l‚0å‚ ªÃ­å Ôê lˆÌ=ÔtC‰{ÐË {– n)ßb¢í€¸' óþ ºpØÐíÐ 5` ç€ >ìi:§ÅS  œ- Ë@?¬ÃöýßjÝ ™ ·) 2 |Ï+20Tp îL•póS]…p`€{d ¯ð±3aMp.¬î` âМöµØ¹-À·œ]¢@ õp– hPgè–Ä^Ñ€ðv¡c¬Ñï—ƒ´DöOñæÍ¢'Gz V¡Â)WäõèpÄÕ‘#ûö%²hÑ=h±AçÄš"‚À‘€¥3|%œ•(R¢„-[frdÄ™ˆ.*ðî\¨wŠ =CõUA¢;4yÐü¨€-þ Eê ½ºŠV“Œ»âÌhðˆ¨ÖªQiQQqâäÈq7Ë]!õ*iùqaœˆd2€x‹q!0¤ s:eåˆD% Ûl-´hÁ£¥Ú³|zX²øYÕ!Uþü1õJ† £FýÀãDz/¨`+TéL=Zð¸Y*„¦7l$¸·ã ˆV¸\¹R¨P…ƒz$¤P!ûAŠ*ìÌ:Ä ‚qï^ì¾gà°ñˆ Ž 8q B‰/f|Îü»t)”ÌàÊ"¯šÀ¤w^ù)xÂ9娢†BNp]°% ÂØE]cžÁJäˆD¼ -˜`þޏ¢*ª©F *‚`«—sÜ‘ãœVD¹à-îXE:é*!ã À #™ Üè / 1‚0€"^ Gx*©DŽ^ò`-ÄèÌ’-šèÁÓü!m¬zÜÐår‚¼à•WÈy…ŠW†Û£¸ §RÁ¦é¸à"G¨ ™9E!.¢ …¸ô …*ëÅFë:ŠF…È;R%ZO"Š@ƒ9¡¾’N⯄þ^z)”B å{NÄ© ZÐE—Lô ‡ ±° ,ØÁ \H04à˜') éel†‰`½¯p:較D¡qÆe–XBœsf9§P2±,“þJ8!… R8‰d+ÑÁ‰*³xæÆ`ø‘j@"l–)d•eëÑeˆ^ÚFŽÍÄÎ*xs4(êå‚UøíÁ0R®à„“B8y®fF+¸ÔÒ›sÆù_n8ù4èì´Ó® 2E5˜ì†®ÀÅë®;/jˆFÝÇ•Œ :Þcd©Õ>þVÒ%_œIXs÷iâF^ ÒÁdH°„3¤Ö,ô64€Ñ*ð0”p1扵ϥ¨WP­À*f4 9Æph¦¹ÀŠU"8f\6ŒÑç®`´_0pöþÒìv¾4ý ×g¿ý„ˆ¦NÓU«¶º"­áû(¤а¿–vu°€õ«PØ¢ýX?ö¡4àkwÊÄ*ìÆ RPÖb“€z¤‚Œp‡1á`4` ‹»º$rêpÁZÀ#Ö„sÀ£Øø×*ÆAˆAŒáY`˜6JQŠbàà d0qTB:بC*"ЀÌ¿ E2DÁ SÔ`e0°!ƒQã à›Ls„LèÀ c8•à Â¥t„Ÿ$#§ EÅNþ:l|:ÐÙø¼Ç¾ò)}\(0Q>H’¯Sá„ "˜ÐCA 4tV¶GJŠàŒU„€¶(໲…*&ÜX².‰LE˜ÀÄ´Øa!ØÀì †"80‚ 8ÇŒ‹}á\9ш+&ÒƒÇU`Žà…&¬1 Pø€QØ f:/ qˆRò8zÌ-th@2qñ‰'ô3©Ø1ÑSÔ#õøÅ±…kà ðØ P²Cáƒ8ê¦4%Xdt¥iéÆP yòÁt¦‡\ R•¶F@Ђ_î0 ]¸‰«87HAþRà,f4c¿úÅ(ž-S«X'’A…z„€m¨8ÃFô€ŒR²$q¸Gÿ¡Ÿ"ä*&¾«3è€ÀŒøÃ“øDDÀ§]Ž£ã€ °Ì âM)ÕFMÑ O,žƒ  8‚E"Ý…ù³&ݹ@á¸0’"â'"¨„ ®Ð€+¤bóHBŒQ‡v¤â׈’‰a,\°„%À‚¤ˆ¢…A8~Á5žæˆÐ(ë‹Ó^PÂpa±ÜÒ‰a¹°C¦‘V÷¥{Æ3Д°A ‚w‚ ‘‚ÈsÞàC aGot¡ŽVðc2ø Ñ,þ‚šåB?åµR¢>ó©UW»ÊÕHÀ?¡p†-Jp‹±â„¡±Æü€¬º5qµÞ°@,ì f˜‡€‡F À…5‡‰Â‚Åêj4[± á‡@\¯ßhÙi¼ApH=»ƒä$È;@ògçQÚv4`ÀˆÀRÁ…:`CÃa& BÀ€#D…$3Mœ2áè©n ¨“’ÎŒ: ˜Ù E|³ÁHw;<Ç7¸Á#ò|D…Qé¤CS>=h4:ÚÍÇv}híjw»D¨T Špü‘[+¥ !ýñï$eãUÀ:“â‚EûÀDž¹…WxþB¼Ç8а 2¨ ‚쵨……¤BÖ0†zÑ9”Ãh1N´¹œï«¸€Æ`:…="8P€ ¡ pã ó@œ1BkdÑžÆ81`äϦ¢¥½ç'"‡z ¡Äqâ\á&p…yu8E-ðÂŒ 'бð…ß@ƒÀÁxÉ» ¢ˆU‡nÀð ,œâ#¥x1væ5÷t'§Òs•[]+ 7¤áDqƒ)þC)åC«¬ÆAÀ/áO Hšà\9D%^qLXbAPV=“± 8œâ ¨xB®yÌ>Ãȃî‡gŠ#þ 8 Om‘œá ”ù-Û‰º1¸€Û>˜G"‚´.¹ ¸Ç=B{ä:ÜbU˜Ç>«x$ß3'6Ì#B@ŽhB?­–Â-¼‰4·F ‚°Œ0bŒ‡f–19-ˆ£ð‚–@£Õ¸ ÖX #Öò0¿7@lbÓñ ¤€âù Æ ü…5ÿU.q³`°Óeƈ€1ê& <ƒÛB† àÃZ-@l-‰‰K„,šÜ\ Áؤ‚#€† ó¨†à‘ $c[rÍ5!À ‚3À…Fà†r0†rH‚FˆH‚x§j±'0H†;HXþ†)¸€JÀ†¼k)úyk€vX-°ƒ„$ ƒ £ƒJ…:˜‡:X·xÁ*Z²TP3è·'¨ÞZ Àpª&¸†hŠJM(;0@„là;`˜‚@`uðBE(‡rPFƒrÀƒ ð=h…ÀE¨àqÃ7Tƒ7¤C5À6ă<Ä5°>´*ð„jµX†B4ÄjX†jx…t©W\P‡@>%ȇ\𚉜Çà|ÿh ™`?[hµ<˜‹(ˆp èAm‚>(&i¦\ó8ð„¯›ˆE0\þ8ÂB!T¸HtP3†YÈlH웇x·Ï,ÜE€$X²|²$à…_hc˜‡'8¡T¸Uh‡yH…$P'À‚y0CØ^ …ThTÀT°¦&H5úš«†LàL¨€HÓzÇwü¬Åü¬ÒJ€¹†O²oÓlX…p°&¶éh\ Í3¸†v˜EEX„$X&Üv0UØ{¸†Î3ѰPPƒÞó=àN… þ  \Äàº5 …"8¸,è‡[df ¦\0äÕ£@40Ü xƒ;Èf¨¾s”=B½3†H„}¼Ð…-†;À¬J—r€shè²5„_°â$86øLÚ‡y† ƒÖGìUcc8œ‡#Ø‚‚Þ²߉dÛjZdZ>ÝFø…ÈézÐãz(„: …s eü†s3ülésƒi,ÂèŒd¨äÆéœä½Úhð“âÀ†â˜ª¥`ûxeh†{( ¯uঠSÌÆ$o´eEèƒ^NÛe®Û ÒbŠ[!È`­{fiQAþƒÅƒPë ‚ "È…\ð¾jX„èa3½›CH{èvx·Ć{ Ùú…^(‡„T„RØ…œý…=à‚X‘bQ…€éÀ…¶G"=ƒøËµÀ `ˆ…>•wÓ£ÝMÐèlÕ-8Øÿ‡ÍJ‚”öcàÑÚmcð_nàöâö0Aîä“⮇ç†îÙ~î_Èï©R°jpêïFê vøÚk0 ½‡9( #X°à‚DðëfEVdk!0ƒ¯Þ°ÓC`&˜;E‹Áå%!‡Á õ4ÓªþL`ðÂT0 21n„DØ‚=ÐEÏ0XrZ„_hlnhZà^CàLàŠú¶ˆÏ¤¢˜ƒv°‡j„Oí*eœÑ0 ˜$È"`„apkÈÓxÁY …J€¨€È¸¡#à‚S¨„ÜêíÇä|+î$ð:èm^ÀOG¦Qh4ÈÖliJƒîp@nÀ†ã®ƒ*Æ=(¢`và/Axú诵ònàf  ,á[`j:؇-`¨´ÚƒXb(u(ƒ{èƒ>ÛXæe¶Û‡¬cÖQÑ'8&ÐB;à‡°ƒh˜‚°ƒ°ƒ˜‚ó¼BO†rþˆ…Xè…ÏòUÊm€èEHCˆ(‡OãF˜‡Ê<&(ßV`]UH¡‹pñཆϪñ€äŠoO!ŒXÒ8^p9ÈfP÷Ç(€ða0… 5YS ´:¨„+àƒ†Wk…u†è…û‚òÿ¥Sh k YÁ:ˆë¾2nx‰Ç^øi^À†ÐM=í$ŽT¸‚)®š¬;N¿¯Aåï"@´ì:ðÚf˜–wô†–·K˜tbHbX€[0ƒenÂ~ú›ÈˆÍÛqˆí7UøáT¸b¿rÜ^è…¸ˆ‹¶P*˜¡ƒl-E@×Dx¼O`‚h(Þ^‡þa V˜‡è7¶IMXæ'Áˆ3åÒDh‚-èÖï®`‘ñ{(èqÓ8÷tW÷I˜„È®{‹ÕÞðŒ‡ƒ Àá*?\‚9 §a˜…à‚ óyð?9Xˆ€hÓ€p}Ö_}Õ߃Õ߃ǃ×Úýw…WÈ9S‚[™JèºcÚàf½ P 7qô¹½†¸„~›àˆ3¸²+&œù ‹ÈKÈq” PýÔG}Ô€=0ÿ:¨ƒÐßiŽZC0Ø{N73`¨V¨Uàú¼í´—]h„½k„ŽCö5I´Ï Á} mIµ ¡þÂ}GM\xðˆªCªüqtä.3f˜å“s¥¨ašÎ¹“ªÕ"¢àÀ¹ÂM„ˆzŽ„À&J—5)uZ5hp¤•8wJåôR*OÖð,ñä‰ê’ªë<ñ´îO°[•c´nkrjÏ® 4k2dlâ ‹§ˆ³PÍlô±…;!‚÷ a‡E°ˆZHÄpß5{öú ÖƒFÔåp´Âý W ÛçJ¢+…+N”S†L±6ÕÊu«V"bÓjEëvlS¿|ø0cfšì#‚ ¥&Ä#¬ƒæÉå…†5Z~ð:B…¥ÊÁ\ñÅû p,ïHN IÏ2ä#bÀž_þî@Í:çÔKQ¼@W'7û¸rE%šaÍ­¨„)m b#?”³ #’ÅHXå„V5ëPÑUUY•è xX³„5-ZãÉÀ ‚ a>yéeƒ 9v˜®($DBür¬°Ç~É™(»ù@Ú©•ø€ê³Iì@W]‚d[D(¶ìEda!&`2·Xž ±®vÉýgOôÐÃóöP¾pÁÅü^ñï…B *€VH¢q“ÊÊU qMlK§Ë&ã6q ×0šÈ1Áp‚—ˆ%‰D*i"•>ËzDœS@*­ÌÇ’¨¤.²•pƒ‚.á¸rDØh"‡•|Õ/óìÁK¼cLÓò’ÊIüâÉ0ÑxÊ´uìQðtÙ\P6Ò€I|bÁ'!è!ÀváXD ÞòÕ‡!ü5˜Bš{1âyþ:úDÑ¡l‰–@!ùäP4a æ˜_~¹æ–ñ„?$`Á!î”n*x—8Ao&¶O*˜Œ8qB¨€ £‰AG\v+—gÄ 0OÂ7Ìs(î°$‡&LÔ# 0ØøÖC%ð¼Mx\üŠ(WáH/DLR‹$1uëÓÈ0ëá &BDñ½Ä‚‡!S”ãG*Œ1ü‹…° &ô°S,â M ä‡à.xñàó—¼Î<œE.–Ö‘ðbgÀ„uµL4Œ„›Ç5ˆž‹©HMÈAŽTB…)Æhº¾“Iq$èÞËðG&paþ†¸YK ÇZ< ØXÕ+ÈQ!a¢î¨ÇzM(à ?ð·%ø;#Xp?"ÌùFoР²í $hÄ™áÀ hÐV]ðq—Plc/} ÌÎÀŽ'N!¬ä7»6á K—r2)„$°ƒ„ z‚ Hð'Ú1'1‚†1¼3˜?Äw“ ^,2@¼ <ã|W¨Ãò˜à¼–ŒÊ53¹‰ªD¡…zô@HgЄ.êQˆ8‚çðAè§Ä˜`›?ÀÜè;fãø›0’`“Bp'F+VcPâDFqA䨡àb„€‰Œ%ƃþ<‚+ SÐL*¤ F½Ö5CsMôbp&tȪ+¡:ôà‘š¹Â3|‡£®ð†sˆ€p†áŽò)1-J,‡ð7 qùxkQË?S0ÜðO!¸‡@âÇ@à ÐPÝ¡ø'_ ‰ , ¢I…3tžÃt¡½¬+( / Ük^Á0—½’D¯š+˜Ì“+æEIèXDH‘¬âåÚJ.'H!8áksËZÉÆ)‡½þèXú„D@A×"ËÜ‘X !—¼D‚̸À=¸ƒ r`I\âšp´ õàB2± QØë r°<®Øƒ:cœš"‚!ü@„öœƒxø‹E¢ñÖ·®£“ˆ/JS `?4@‘P좞'˜ËŒì"ˆ{pk/ì°‘ž€  §…+%'zÍë **ð€¯_!x@0 ÚƒØË^1žWjLb×JÔ³ó¢±½\<â'| ׸†ºîÕÛÞòöµ8¾é>r›Ã ¼)¸'Ä;K”V\ÀDæ1Œ^4b>ø¯1Œ@0fºÌæÁ4âIþ¢&4Ñ 4ø`a•Ð ÈaÕ£\xƒÈ¾ AP"-ܘ‚“˜‡;Þ:‰|L¢uðA=r¢ lÀ'ódBžUcˆ$ .‚ÐgQ„ 'V0¦%Á$]$KRò·Mm—÷µ/}á ¼èr¾:{/|-»³9Îqå%í׫ÆTF6´o›ŠœGz± §%?;_’åmœ¨Œ‰+Ÿá üw*°134Ì!ˆ€!ºYŽ<ø€ b"¤°\çò’—Dp&Ľ•,Å©áèó*!}‰7À1-Ä!ŽLT¼0Å2À‹%àÏL¸o>‘`0b¾Ùþ-äðŠdÀC•¸61OMd׋ÈC;·Áž`ÖyÙ‹sîv£"HºvE08Kå7Ý´Ø!ÈÖóµ//ç‹ÄÖװÞõ ãøÙËÖ׿¸pusG ØvFÏNåØ[Ø[÷²°ûÅÂ3@Ø ¨Àß  6¾Ÿˆ@ò0…g &ç…¿.8f±`Æ$Š'¶§1O³h¸kàÐçBH¼ðøÁ+ QhŸÉA ¯A! ÀÔ¡¼˜Ä$hAòöLÂA‡#bãMP"xÅNÁlЂVš†˜ÐŠaC3ªK\N€Yë¥t0ƒ=Žô&¨À´ þŽ€ *×1‰Á—Á.l¬ƒ·þvÿW¸Ð€~ý ü÷×°é üÁxÀ´Û¾¤—…@@*lÛþå`‚ÿ¥ß]ß ^£a ÿíŸÿõÝ@ žAÞ< äÂ}ñCà)@Þ¿IŠHÁ 8W/áæ8HR¹ƒ)ÈRäL=t?L4BÀŽàQ©À<ÌþC¤NzÚOÀ/XC/$A,‚! 0åÒ0Œ™1˜M!ô‚\Å\âÛDW6@Nzå¶ñâb Ö44š¥(rå v¥WÎÃú€1(å© RˆÕ,¼ˆDƒ}©ã­G6fÀ×@Ñy@8²¦„{A6 ÞØÌ-4S‘Š Á©pCàÄpôRñXJ8^(©š]ƒÓŒ |Â<Èϧ,U¿N‚üàOLB9â?d(/] {0å dJ¥¬å½Y«f(t(-x£¤\Ã䬛é’Hdþ#¬ƒc@h‚¹èRd~„g¤ 6àDªÜÄ4ÈÀ(¤@ ‚ P ¤ $+€€ h.Àƒ³ÞU=˜ÂÑ€Ò´(4‚;üÂ\N±ÃŒÀ]ìÓ |éG~.Ä)äê)Á€ÀeŠ[1¦QÀê¥þ ªZáãbÞ^âÞââ}ª%§2ªáž}ùéå2.çšêœbî3àé}a®8ÂŒçZÞð  Šª_ÆB†òÃ3|1DËLÜnsYè_f  €tôÐÂJ¸h/è‚-<Ô„CxF% †©`Ã)Ȧ.Üè€ \¯èÂŒÃ8¬BªþüÂÔŠÙÊÁ"ì™±-t$‚LPqf$·,€^Ð.4€¤Q6àÜ)@À)„Ã*ÀÁ ý ”Oê–j{Ú#È'] çBnæM°X l.…ä&î.}®ÏËäƒ..©°©&lê¦ððàOså?|l ?-€hy ÜîÇÞî©þ%tñÃ<üÒ4@• ¯‹29h À-à-Œ†àD2Äæ*ˆB2ˆøŽCòÊÄgøDN)9aS(…!ˆ@/ü‚ûâ”`AØq®k;´+\Ã"àO9œ!’Á)œÂÀ]΃ êâæþ$¤‚©šj犰Oò„2îã²G,¨êÉbæ,æÆ°åYÊ…^n6Ü}yì}±  7ñà  Q.ðìíþNð„n,Û0©–2tÀIÔ"¡/ñR~hB¨‰€°”i N †L|I?¯ó­v1E+DÀ‘)”+Æ © ì€U÷»êøœ@H/DgX£Á*Ø3¿ €1´B9ü€œûp&×é&py\;´'{r–óµÉ/p¾¼Ëwþ¹A‹r ·˜·ªë¦4Ìç²­óC€6?x!€óƒ8pcûÃÁ„ü…Œ{dA®¦ÔßÁÓW›¬x¥B‹Z¸Âû,Ä;غ;¼Á+l•LŸƒÆù;k!(¤–ºqN W뜂 †`ôC?ØÃ-\õÝ.B,<ˆ Á,,ßW2X`Â<‰m€ÂðÔ<šGþ°;ËWþÈ£¹É7ùËk>äË|Í<+;èË9sɹäK>H§‘ÚA4Ìä y6¸8/¸9 .Õh5è¾Ô¯¦jJýïû>TÀ‰½Ý'ªÒ¸h¼/1iÃ{ ´@óÇ{ <Ϩí|Àþá”ÁëtÌt‰`$‚¨3.˜Á'¼8¼Âú/A8pA%øqtN/Æ+ß>ÖC*0‚(ŸyèGþÈ<@lŠ5`A‚üˆŒÅ!à n‚¨p!¿Šf„Èп\ü¢ñC"2H$#¾ðè1Z´ѲeÃhF ™Âù#P6q¦xù(à(Q ­ÎiQª´Å%K¡jiÁtªB`ÂtÓ“uL¹s ”&Mb_S{NÜÚ¶iuÉÑDV“œ<‹RíÛ÷„ï^¿zõ†¸R ;v!žI$Dˆ=:Xl<¥åÕ+]¯Zp»rêϧ’]€³ L‹°-±&ÎZkkKþ–a„ÓNÇ3>4øð6ÄÚ¿^´Í°%˜S²Méí;ÚI˜:{vì2Z Œ‚yjª8Ö-Àƒ÷nM­=¼>õåH+wKîX»#N‹¸;RÇÇ\¹òTxWBÈ*v> áš=€9˹È*K¹ê’ËZè’C,PŒ‰ ‘½úÌC!ž`Çà8Tû‹1!r¦]`Ô…] `Ï>[ådÎ(¤=ÂñA±ÜÑ2þÎ "›çdÊI' „2t2Á*³ùÀ-sŠ©¥jãç·1šÂ€ì´Sm‰u¦ó$ãZZÒÊ‘íÊ@¦hsÉ@Á/??õÛ¿þ´Î1åö`@½õZÑe>ïò‹tÐIû{ã ¯0 0@¾*H´²̪k®E|hàUôK½@Ä„'*ÑŒY_õpŸWŸÈD®_ÝÑ2:#ƒÈXeš7\)­’$Ây…œ b¬³ÕÚRkPqöãöœA[à/RÖ^‹<íÈsЍÍL*\[Þ%Êq·6$²9“ Øø ÂäÜÍ3_*ÂÅÐýÀ›ô²Ý1Å|TåU$>ÊHÃ¥aþtiá kÉÁ1Äø"ù‰½"HÅ`hiÅP˜`”ED1¦ØÐ¯“OÎõÃså 8Èx•“ó¹ –XKþ-«6ÓGb“yCQBèZD‘‘œ¯Á–Æ´Vã³_ycÐoÙNËšÙzʆªY»»_û7Ït [×ü8¦Ä-—ÈV\A½Ì²j«%Ç”J  ‡E- EnÑV¸2È|¥„@ D¯žº/¾ž¸&X÷ç]‘Ö5ivdMlŸÁÎx`ö}tÖ+‘YTó®-?*¹Ybqç?Þð±D'“뱿ž9Àž±û¯AÑûðAçØ¶¼;çüoÃón ÃÕe!qmY;wŠ–ÔÍ“ð)Ÿ¥µŠô8Ëpï{âóÚ×äà°  SQ,áΡÍq ‹þØ.@Ž7#g`êTÇ:ÆŽ„ÒKírÅ:ÅäÊܨBà WØnMÀïu/{Æì¡*ÁBdªgõ$ Oþ§©y$æ)ÀÀ Övá ž(0K½€ Ÿ9– ‡;¼Az  DÑÒ–º2–¬ýiP…Ûau¨Äœ­mo‹ÔdV•™¼¢3úP'–eAähj&@w¨ažžXÇ:œ»kœÃ,muDBà@‚2±‘ }ä^z=dÆRá°¡œá š¡ìN"’]#1º³+²‘rG[e0›Œ—÷˜à¬ @Ch€Ç)TPn¼2µªµ0y- KÕ¶–µ¯t­†*ÛØõ˜º…(k=C1š(V1R“ÛÄϦhP©4a k¢¿ØC®Qþ”¹ÖÕ»z…¤ýêJ̆£pà†z3 Ã¸·¾%{oöå&4!Ë€É {Ï`J0<Àh>L ¡ÒÌŠ¢•†‚l´`<€ zXÅzW%Š@À˜ ðJ+Üg ·´Â泡-T‡øµ?µíx‰šÛcšâ¨M„±Qg«c_ rhEžªÂ¢ ÛØP6,^1ªü„4y1û `Ô $ ÁzÙ‹ ÃhÊd‰‘ë ôåœA½ŽÕC%°ACõP*€†ÔúYx³‚9K`°7ECÅH´D?‹BÚã7õ¨'`u¯YÝ—U7KÓmèB#:Ñ‹v­PI\þSŒ·&6qérŽ´®c LàÅuE-×C@ág¹`¹ÇêhšÓF4E+.Þ Ђã´h„Ð íp„ãá0F“ác¨I€ƒR‡Jœ|æ¿ð̃ŽS,[¨Ø•í,ÑJ@¿ î‹ö€S¼@EPád=˜[æ4Õ±þ笻ÏF÷´å­Z°SÝñ_EìS™ (qÛmL–YøŸÃÈ-’ðÖeb– E&ŠÔ½†fÕ¸÷m2MQ·B­ …/‚FH ‹h„ÆËÙF`U9Âú’ƒä¢èE±sÙ\¾ïØE mTþÐtˆH: LèAZw82¿u?›×êůú’‘oõsWXøæ¾,ÙéMÞ´»2ñ”>æÛÉrb9¨eî~˜ç,†1 P4uHø\îïU3TTü#T!47HßõÏá" ߊÅëÿ•úw¼þÝ4ŽЀkD¡ã:®ñÈ-õÈ´ à r¯Vɲ.K¢º-¦Î`NtÏD¶ø‚oÚšï÷ÌÍøŽëÆ딯¿.Ã* Ã~êâÊ"ftl¶f0¹Èž+žÖAžë¹zaæÁüøŽÔ~ðÆçkŠ‹ý¶¶‡·P,¹à N¬²Ò Aß¶°ú‡rè ¿þòò¯ÿpÿ.kç¦(  ‚ÁÙš€ê ÿ0´1Oò6ŽÂèfïÿZ¦7[JãRëñRCý ýãì-LO²±‡â.“.hŽ AÈÁÎ:aq.Çé‹è;éŒòÒ"Å)Tór/aÇ|¥T|%0'®0]ŒÜ“! ››@ÈáÄRŒ ±ç +@¿ õ%o°ú`i áçЕ4NB+T++qñˆQPE ëQã>nãoã"oÿžUPÑ`ñu‡†Ñ¶jì¶ÜN]4çWÉâ9+à Þ2 ?F`QÔ/"1õ:»sH‰TŒË¸B¥‹~<þÛóAÌB"å©ÌÌ«%“e¬@Zo\¡Dü ä #¡($Û.d}ñ 7Qµþ¶&mr‡2®°õâ2N‡BÓeuñ$”\é0ñ u\[FÿðÏ\¥•ZÉ4L{h]Û.QÙ5$ÙÕ/éB°a* È©ë’_aQ,°“{>•;© õraÛï_ƒ#qìAÎa­¬”W£©à nY@Vá õ‚Ð`¸aWeloÖÒ\Td)Í?õX¯ ËT‡RRZðþÀ0%sèZïâVÖAk²LQf a8k2ãu · M6ñþS=•ÖIRþÄ0ÛªáF׃j%Rþk5ukÁhAüÈ` VT6l½Sȳ¸¾Æ<©ˆTê",KbAà Pàéô"˜à € 0ÎÒŽ©¨”$Ol×Qm,s·Ðí<·r…q|=·$õ­Æ@WÓ2·|Ùw8MÆWÇ W GWXkÌh«IÒ?ÉâeLw#7¹@Ax!R- ^ÏBGÁÈB0u;Eåv-Ävw·`Ç–wóò ç²lË–3V©’äA/|ø¨Ê<ÿ${U¼’6iù7klÇ7k² ‘vÙU‡Õ+Óõ?UQóÞ·&a†‡]ÕE5ÁzA|M `FåÀð@乿¢qþlu[wQ,!ýÊÉ:ù•‚˜.‰ä!9•SõUwñ².º¨G'xl¸'üÂoaÍS¥ä3Y¬ 0!&¡.°L XÍó¸¦#U{5u}1$m̉˜ stÙõ?ó× qŠ)™0™ @Ù‡ÕP·A(Y‰s‘ †aîðÀfAþä@ú±/µ¸/[a^È(’HÆXŒÏgkuùŒ9uáÄxH·v.÷•_?&f!â)‚ð¹ g$– F¬ 0‚‰‰¹©–X0“Ø0Ý•t•6û X0ýò`=—X€ÛY]uþ@a±Tž³8dX;™¶T˜Jèå¬Ê¡ÓþÀ¶lVaãÏÓxá `Ç‹©–H6™Í8m×vyY|¾ˆ{zAS½Hkw”˜Ó"gÁL ¤»L Tšt3V™n÷¡,Kž­g‰ÅYÇ ™Ú9‘³¸±83A#Y‡:–[ì<)nÿR€ñÙç¯/ñk°©KÅ‹üÀ<¡öªƒdùà¢s`7˜}9¤-z¢ù‹†½È_µVÀ -ÒxÄ¥ç& ºA¯Ëj P`ˆ>ƒ ÆŒJX/* {U{±0‡]¬,>=™¸AXþÌ‚¨¡09–­×ªû’x3RI5²+9’²¯¸©¿V†A˜À ¿Öþ"÷Bü©Z=à˜…Y­k·vÏZ—ýH"q[·_á|ÀJš ¯÷Z¯Oº¨GNaôàH ZÏ‚N®gd5Í05‘e¬Q[l³‘úE3ÛŽÿ’.ZŸL•³9»µ`swTS›G+º.å²w·]ŸŒy‚ÙÜó ¢±ËuÇCÊ€ \·¶!¤œHÌ|ÕÕÝP†»ËþaD-Àˆ˜eý2ФÌù#ŒbDw{aᡨ¹38 ´ÍP0»‘‚¢J®]¦†Û ·–ýБüÛ­s£Õœâx_'XÓß j/Ûq7åž®{yÝçÚÜu¹ò]·ÏØwóÒa à ª( @,„à?‡.ÿ½2Ф€¨þÕ¿¥ß‰ù[>¦2Ú&-Ò&¡ÎácrœP-T2AVa Áæ,Áø°Ùf¨GH€ä~5a !è©êؼíøW$ýA*ÝljÜB°ÝçÕœXS_èÕ:Á#òÀß‹†A,._ÛY×9±\},üñåúñ×ÚBÚÛ/ÿþB~¡r¦¼( ÊÊF뵜˜½þ ئêÛ-Ôì¿þ ÂåëÁ^¡è’ßA§{øìÎàŒÌâ^ï°±<Þêh PÐ鬞«ŠÕ‡< ?TÁ œ,üÞƒyô½˜Èl?-ÎßÂhà¾v¿ÎþÏÁ^aâ­w¿—×b}ÔÇæõÿçÂÀ½tÍše°×9]g¹ëåΔ.*¨:¤ÊŸ?(´4s§ ä¹W#Ï™Ô5ÒI’&_©,‰²äË•%_½jqSÜH›;mêré2¤®¡CÉé"‡”\2xÉNA CÂzPs…êŒÖ3pD‰!j‘5ëÖyò„'­8?çfþƒ(GÎC“ {\ëç`[“|ù²´Ùâ Onöb²oËY~°xÐÂÞh%èí`Zh£~¬‡”fDäÇøñ±Ѐ™û@V9/‚±!Y§&œhÌæ:Ü(GtÂñ`Ó£Îf‘ÙA #µù±‘‘^Üç8;P…lRª™T 0–šPe¬ B`S–aÈHU¬‚ÂÍ„–B%%,b·#‰FƒÔ;„ýJ!Í[ƒPÔÔmš*ãIÀõ !䈚nª‡$# ©ˆ€ €¡‰7€ä0nyƒ]þ`?‚dígljF;xþ‘œå„Ÿ>ýh*à žXÂð¦·%anœ§ ÙE.Žó›ìc$3×È-NjdìASªJµ& ŒHÙÚÊ1 TQÔF¸ÙßL‚(Œ²R£ s% xuÒ%„ô¤ŒP\ËXFù} ó4 <ñ´7•˜‡ LÏyxÃb&8OP~bã!ËÙ>~賜ï;£nß§ÛøÁÏvó„VÓ)¯‰L~j$ã6·¹9Ìb³žúœgtŸ{Æ©cˆ¤\‰>Ð fЂ(ò ©Z†š̓„¨3Å9¬±3ĪP]bÅ!ÖuÐ)…ÍX`‚@8÷$ûêɾ2®ïþ€&  ðÐ/?ô¢{½ðÈÈ(¢³ý!q&Zœ{ÈÚò6ªÝ(ãn{‹M~l¢·ÁU#è92Ք̹Òm®mw‹MÌV÷ÄûTS¹)¹j÷D“ 2]-‡Ðó¦mt‚-¡F O ,rÜ•|ÅQú.,Žë`„$M@À}À6Ù˜;{àAö‘Æë;3üˆ`‚ 7j|³p? ã1fÇÓUä7AÆøñ¹ÎÃns…èC/8³ÕUsgkŒãFG›!fªƒ¼©Æ®t-/’K•)SMÔÉþ€²XPÙº1"6pTC¢–¯8z"ÌF‘EÖà)dcüøÀ¢±`?ÛÀþ#0˜ ùйÍ5 pihc·ÏÄÒ¥jslc5¾/ÑÃ%Â&¾½ æ—Æ5Æv¹Ièh›êËæßã ™c‹Ã5¦Qä–®ht‹¨CH e<0´²©f .*FŒ•¡—ä­ë}àa™ž 7š‰ñ÷-;Øó̬Y ÙCsûª…æfU­ŠèMàY屨D,ZÎ"Èœt7ü^>g:ß<~tî¹Î{®â– ]ç47´ÑCþqŒ«ùݶžë½õÊA—Áh©ØÀA¡†0ÀOõÁ+{¹{9Àijaë?"¸×jôÄù ³ÊÝètç¹Ý_Lô¼ûüå.þw9Ñûs¾ã}± ÂË _ø#Zñu'y`|‹êEplÎRšÌ“æCê…ç?ŸaLØ=îA˜`C,bõ¬o„ë `ÀÞ´O‚ím?Üë>©øÄ5 pk°*š‚ ¶Î‚ƒâønþ¦—mÖØ!Ñ@ܧO}$Dîw®>2`ýœ‡ßâÐîõYí@äNßUÆ ÂªaƒK5Xã,‚0ç+| O¸{Ãȃ&˜@z§—z¨—z­{± ¿ð çáÆ >À X¼©R8#¼Ç{ªÕØ` ‚#H‚ð fð )¨‚  ‚× ‚¾w‚þÁç‚3|¾|Žp 8(ƒ;˜Á—?øƒ[°M°×` à ÷±Q¦¤A{‘œ—y°Cðyr½`o€îy €‹zªÇz´Ð¿€€Æ{pP{¼{·§{ó@耇xÀ‡%(‚/ˆ/ÈŽÀ,ˆ†¸‚…hˆˆˆ‡Øˆ+ø ,(‰Žøˆ•X‰.˜‚×€‚0¨‰5hƒ;(ƒ@(Љ°‰°§¸MÀ*ªÀ°‹%ø |8ˆŽðŸ-Ȉ6¨ˆ„¨‚„Œ0ȉÂè„8ˆŸà!p ƒO`‹=p Ðh‹ÅèŒÁÇŒ‹Xˆ˜þ‚ PŠø h‚#È‚ÝXÀáøßXŽ$X³È,h‚”8Œ»˜‰/ˆ‰€8ƒÂHƒ È>Šþx =hÿ„9Ч(‰û`ЍhЦx‡ „[`¥„£¨‘‰ðýØ‚ÃhƒŸp‹÷˜‚¹h‰€h’)x‹õØ3x‹ “×Бùø‘úƒÌˆÊ˜‹Ê¸·È“˜˜Á“3Ù’B)“G9”EÙ’1Ùƒy y”EÈ?X„Ù@8• )[ù é•™G–‰0‘ª‘by])Š^iûЖOЃE¹ƒ8h—KY”O”z)ΓBù=”Bþ9Gi”z˜Ñ(ƒ{©˜üH”ýø˜i˜H <è”Mé”O°šé¢hkyŠ)š@˜jù•Tiš)–_ 9‘ ‰Š )² ›°éYY𣸔¦ø”½Ù”EH”0i~9™‡ „Ù”qÉ‘` —?x”=Ø”D¹™r œ“É‘Åù›½Ù‘ ùœ£‰š§yŸ –šTš^›íéž\¹ž¦Ÿ_¹šc)–G‘þ‘m™šóÙŸä9šÈ) æù™P)º  `9•»9• 𕉀œ:šþÉ Ì©‘*žª¡âé¢ù•ÚŸ!zšìiŸ©i cy¢ YŸ Y–þy› Y¢ôÙ•ª™û0›³©™5ª£›‰•9*•O¹£pé”Õ©—¦È™=PFÊ‘§Ø›Ã¹ް¤>*¤2ÙœBЛ¡ —R*:ê›—i¤§è£íY£±9¦îi¦óy¦ª¢+ª¦_¹$*£l*£SyŸ×€‘PÐ{º§û°–0„‰À§{:„|šŠD8„[à§M ¨ ¨Gð§[©~J©Šj©ˆ:©ŠÊ¨|Ú¨ˆê§j©•º©žÊ¨¡Ú¨¢Š¨Dاªº¨‚JŠMª|š¨‡Z©µªº©§z©® «›z©}z«‹j¨¿:¨½ºª„Z¬Éš¬‰ª¬È*«½êšwÊ*ÓJ­Õj¬­×Š­Ùª­ÛÊ­Ý:­ªè­úÙ¢®I®ãj®åŠ®çª®éÊ®ëê®äÚ®ñ:®áJ¯õj¯÷НÕJ®­Y–üº¯yÊ®þÚ¯‹þj°« ;® ‹°{ù ±+±Ë­òÚ° ‹®û¯›±û®ëª±»±ùI±%k²'‹²Ó°û®!‹± ³/+³ ë².³-š²9«³;+®;²5û³{³>û±˰";xjig-2.4.orig/rotate.H100644 1750 1750 13461 6175520157 13064 0ustar davedave // This include is meant to be the body of the function CreateTilemapXX, // which is implemented exactly the same for different resolutions. For // compatibility reasons this is controlled by Defines instead of templates. // Therefor the following type definitions are set to the required values, // while compiling that function: // // #define DATA_TYPE unsigned char // #define DATA_PAD 1 #define IMAX 1000 XImage *ximage; Vec2 wcenter; Vec2 dirx,diry,edge; if (page) { if (pm->IsTwinPixmap()) wcenter=Vec2( center.X(), pm->XHeight()+center.Y() ); else wcenter=Vec2( center.X(), center.Y() ); } else wcenter=center; ximage = img_buf->Init(width,height,DATA_PAD); if (!itm) { if (page) { dirx=Vec2(-1,0).TurnAngleDeg(windir); diry=Vec2(1,0).TurnLeft().TurnAngleDeg(windir); } else { dirx=Vec2(1,0).TurnAngleDeg(-windir); diry=Vec2(1,0).TurnLeft().TurnAngleDeg(-windir); } edge=wcenter-offx*dirx-offy*diry; } else { dirx=(*itm)*Vec2(1,0); diry=(*itm)*Vec2(0,1); edge=wcenter+(*itm)*Vec2(-offx,-offy); } #if (0) // // the traditional routine to copy each pixel from one image to the other // with the generic routines. range checking is done in pm's GetPixel() and // there's nothing to worry about (except the time...) // pm->GetImage(); // to make sure the pixmap is valid for (int y=0;ydata + y * ximage->bytes_per_line); for (int x=0;xGetPixel( XPix(pt.X()), YPix(pt.Y()) ); pt+=dirx; } } #else // // optimized mapping // in a loop in brezenham fashion, each pixel is copied from one buffer to the // other with direct access to the data structure. Since it would be inefficient // to an access outside of the source image on every pixel, only the 4 edges are // check, if the boundary is crossed, a traditional copy with range checking is // done. This happens very seldom, since the buffer for the picture is // large than it has to be, so that only a few flip's will really fall // outside ... XImage *src_image=pm->GetImage(); #ifndef RANGE_CHECK { char *src; char *pic_addr=src_image->data; // image start char *min_addr=pic_addr-pm->offset_bytes; // memory start (including offset) char *max_addr=pic_addr+src_image->bytes_per_line*src_image->height +pm->offset_bytes; // memory end (behind offset) int count=0; Vec2 t=edge; src = (char*)((DATA_TYPE*)(pic_addr+YPix(t.Y())*src_image->bytes_per_line)+XPix(t.X())); if (src=max_addr) count++; t=edge+height*diry; src = (char*)((DATA_TYPE*)(pic_addr+YPix(t.Y())*src_image->bytes_per_line)+XPix(t.X())); if (src=max_addr) count++; t=edge+width*dirx; src = (char*)((DATA_TYPE*)(pic_addr+YPix(t.Y())*src_image->bytes_per_line)+XPix(t.X())); if (src=max_addr) count++; t=edge+height*diry+width*dirx; src = (char*)((DATA_TYPE*)(pic_addr+YPix(t.Y())*src_image->bytes_per_line)+XPix(t.X())); if (src=max_addr) count++; if (count) { DBG0( "*** range overflow -> trying slow mapping\n" ); for (int y=0;ydata + y * ximage->bytes_per_line); for (int x=0;xGetPixel( XPix(pt.X()), YPix(pt.Y()) ); pt+=dirx; } } img_buf->PutImage(dpy,tilemap,DefaultGC(dpy,scr),0,0,0,0,width,height); return; } } #endif int pixels_per_line=src_image->bytes_per_line/sizeof(DATA_TYPE); register int dx=(int)(dirx.X()*IMAX); register int dy=(int)(dirx.Y()*IMAX); for (int y=0;y0)?dx:-dx)/2; register int dy_c = ((dy>0)?dy:-dy)/2; #ifdef RANGE_CHECK register int src_x = XPix(pt.X()); register int src_y = YPix(pt.Y()); # define INC_X src_x++ # define DEC_X src_x-- # define INC_Y src_y++ # define DEC_Y src_y-- #else # define INC_X # define DEC_X # define INC_Y # define DEC_Y #endif register DATA_TYPE *src = (DATA_TYPE*)(src_image->data + YPix(pt.Y()) * src_image->bytes_per_line)+XPix(pt.X()); register DATA_TYPE *dest= (DATA_TYPE*)(ximage->data + y * ximage->bytes_per_line); if (dx>=0) { if (dy>=0) { for (int x=0;x=src_image->width||src_y<0||src_y>=src_image->height) { *dest++ = 0; } else #endif *dest++ = *src; dx_c-=dx; while (dx_c<0) { dx_c+=IMAX; INC_X; src++; } dy_c-=dy; while (dy_c<0) { dy_c+=IMAX; INC_Y; src+=pixels_per_line; } } } else { for (int x=0;x=src_image->width||src_y<0||src_y>=src_image->height) { *dest++ = 0; } else #endif *dest++ = *src; dx_c-=dx; while (dx_c<0) { dx_c+=IMAX; INC_X; src++; } dy_c+=dy; while (dy_c<0) { dy_c+=IMAX; DEC_Y; src-=pixels_per_line; } } } } else { if (dy>=0) { for (int x=0;x=src_image->width||src_y<0||src_y>=src_image->height) { *dest++ = 0; } else #endif *dest++ = *src; dx_c+=dx; while (dx_c<0) { dx_c+=IMAX; DEC_X; src--; } dy_c-=dy; while (dy_c<0) { dy_c+=IMAX; INC_Y; src+=pixels_per_line; } } } else { for (int x=0;x=src_image->width||src_y<0||src_y>=src_image->height) { *dest++ = 0; } else #endif *dest++ = *src; dx_c+=dx; while (dx_c<0) { dx_c+=IMAX; DEC_X; src--; } dy_c+=dy; while (dy_c<0) { dy_c+=IMAX; DEC_Y; src-=pixels_per_line; } } } } } #endif img_buf->PutImage(dpy,tilemap,DefaultGC(dpy,scr),0,0,0,0,width,height); #undef IMAX xjig-2.4.orig/reset_image.H100644 1750 1750 4617 6172754226 14040 0ustar davedave // This include is meant to be the body of the function ResetXX, // which is implemented exactly the same for different resolutions. For // compatibility reasons this is controlled by Defines instead of templates. // Therefor the following type definitions are set to the required values, // while compiling that function: // // #define DATA_TYPE unsigned char // #define DATA_PAD 1 DATA_TYPE *xdata; // create buffer for Image-Data // there is an optimization in the rotation-routine, which sometimes tries // to access data beyond the allocated image, that might lead to a segmentation // violation. Therefore, it might be good to allocated some additional // rows of data for the image. offset_bytes=xwidth*offset_rows*sizeof(DATA_TYPE); xdata=new DATA_TYPE[xwidth*(xheight+2*offset_rows)]; { DATA_TYPE *xdata_run=xdata; unsigned long blk_pixel=BlackPixel(dpy,scr); for (int i=xwidth*(xheight+2*offset_rows);i>0;i--) { *xdata_run++=(DATA_TYPE)blk_pixel; } } xdata+=(offset_bytes/sizeof(DATA_TYPE)); if (!xdata) { fprintf(stderr,"not enough memory for XImage-data"); exit(-1); } // create the XImage ximage = XCreateImage(dpy, DefaultVisual(dpy,scr), DefaultDepth(dpy,scr), ZPixmap, 0, (char*)xdata, xwidth, xheight, 8*DATA_PAD, xwidth*sizeof(DATA_TYPE)); if (!ximage) { fprintf(stderr,"\n*** can't allocate ximage.\n" ); exit(0); } // copy data from original image and inserting pixel values on the fly if (Width()==xwidth&&Height()==xheight) { register DATA_TYPE *copy = xdata; register const byte *org = Data(); register int j,i; for (i=0; i0;x--) { delta-=xwidth; if (delta<0) { delta+=Width(); *copy++ = (DATA_TYPE)gif_cols[*org]; } org++; } } else { register int x; register int delta = xwidth/2; for (x=xwidth;x>0;x--) { delta-=Width(); *copy++ = (DATA_TYPE)gif_cols[*org]; if (delta<0) { delta+=xwidth; org++; } } } } } ximage->data = (char*)xdata; // XPutImage(dpy,pixmap,p->gc_all,ximage,0,0,0,0,xwidth,xheight); xjig-2.4.orig/Makefile.Linux100644 1750 1750 4401 6173244317 14164 0ustar davedave ### compiler section CXX = gcc -Wall -fstrength-reduce -fpcc-struct-return CXXFLAGS = -g -DUSE_MIT_SHM ### default file to be used, when no options are set JIG_DEFAULT = \"tina.gif\" ### Directories for include files of X11 and libraries X_INCLUDE = /usr/X11R6/include XLIB_DIR = /usr/X11R6/lib ################################################################### LDFLAGS = -L$(XLIB_DIR) .SUFFIXES: .C .o .C.o: $(CXX) -I$(X_INCLUDE) $(CXXFLAGS) -c $< LD = $(CXX) LIBS = -lXext -lX11 -lm OBJS = xjig.o \ objects.o \ stack.o \ imgbuff.o \ puzzle.o \ real.o \ vec2.o \ vec2list.o \ mat2.o \ color_mapper.o \ gif_image.o \ gifx_image.o PROGRAM = xjig all: $(PROGRAM) $(PROGRAM): $(OBJS) $(LD) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM) xjig.o: $(CXX) $(CXXFLAGS) -DJIG_DEFAULT=$(JIG_DEFAULT) -c xjig.C -o $@ clean: -rm -f core *.o $(PROGRAM) xjig.o: xjig.C objects.o: objects.C stack.o: stack.C imgbuff.o: imgbuff.C puzzle.o: puzzle.C real.o: real.C vec2.o: vec2.C vec2list.o: vec2list.C mat2.o: mat2.C color_mapper.o: color_mapper.C gif_image.o: gif_image.C gifx_image.o: gifx_image.C # ----------------------------------------------------------------------- # dependencies generated by makedepend # DO NOT DELETE color_mapper.o: color_mapper.H gif_image.o: gif_image.H gifx_image.o: global.h gifx_image.H gif_image.H color_mapper.H reset_image.H imgbuff.o: global.h imgbuff.H mat2.o: global.h mat2.h real.h vec2.h mat2_x.o: global.h vec2.h vec2list.h mat2.h real.h matrix.o: global.h matrix.h vector.h real.h matrix_x.o: global.h vec2.h vec3.h real.h matrix.h vector.h objects.o: global.h objects.H stack.H vec2.h vec2list.h mat2.h real.h objects.o: gifx_image.H gif_image.H imgbuff.H color_mapper.H puzzle.H objects.o: rotate.H puzzle.o: global.h puzzle.H objects.H stack.H vec2.h vec2list.h mat2.h real.h real.o: global.h real.h stack.o: global.h stack.H objects.H vec2.h vec2list.h mat2.h real.h stack.o: gifx_image.H gif_image.H vec2.o: global.h vec2.h vec2list.o: global.h vec2list.h mat2.h real.h vec2.h vec3.o: global.h vec3.h real.h vector.o: global.h vector.h real.h vec2.h vec3.h xjig.o: global.h objects.H stack.H vec2.h vec2list.h mat2.h real.h xjig.o: gifx_image.H gif_image.H color_mapper.H imgbuff.H puzzle.H cursor.h xjig-2.4.orig/COPYRIGHT100644 1750 1750 5220 6175454654 12732 0ustar davedave Copyright 1996, Helmut Hoenig, Heiligenhaus/Bad Camberg email (for any comments): Helmut.Hoenig@hub.de smail (for gifts :-) Helmut Hoenig Hopfenstrasse 8a 65520 Bad Camberg GERMANY ******************************************************** By the way, I am collecting banknotes! If you want to join into my collection, get any bill of your country, sign it on the backside and send it to me so I will pin it on my world map. (Don't forget the exact location for the pin :-) But you can also just send me a picture postcard ... ******************************************************** Permission to use, copy, modify, and distribute this soft- ware for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies ----------------------------------------------------------------------------- The demo picture supplied with the package (which I can set together by heart in the meantime) was taken from Panorama-Disk 124 with license free photo's by Dr. Lothar Rossipaul Verlagsgesellschaft mbH Menzinger Str. 37 80638 München ----------------------------------------------------------------------------- The loading routine for gif images was extracted from the gif-loader of the xv-package. It was rearranged, enclosed into a C++-class and enhanced to use extension data for some game specific features. Here is the copyright note, that was contained in the original loader: | xvgif.c - GIF loading code for 'xv'. Based strongly on... | | gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image. | | Copyright (c) 1988, 1989 by Patrick J. Naughton | | Author: Patrick J. Naughton | naughton@wind.sun.com | | Permission to use, copy, modify, and distribute this software and its | documentation for any purpose and without fee is hereby granted, | provided that the above copyright notice appear in all copies and that | both that copyright notice and this permission notice appear in | supporting documentation. | | This file is provided AS IS with no warranties of any kind. The author | shall have no liability with respect to the infringement of copyrights, | trade secrets or any patents by this file or any part thereof. In no | event will the author be liable for any lost revenue or profits or | other special, indirect and consequential damages. xjig-2.4.orig/Makefile.HP-UX100644 1750 1750 4403 6173670537 13737 0ustar davedave ### compiler section CXX = CC CXXFLAGS = -O -DUSE_MIT_SHM ### default file to be used, when no options are set JIG_DEFAULT = \"tina.gif\" ### Directories for include files of X11 and libraries X_INCLUDE = /usr/PJ72LINK/X11/include/X11R5 XLIB_DIR = /usr/PJ72LINK/X11/lib/X11R5 ################################################################### LDFLAGS = -L/usr/PJ72LINK/SYS/lib -L$(XLIB_DIR) .SUFFIXES: .C .o .C.o: $(CXX) -I$(X_INCLUDE) $(CXXFLAGS) -c $< LD = $(CXX) LIBS = -lXext -lX11 -lm OBJS = xjig.o objects.o stack.o imgbuff.o puzzle.o \ real.o vec2.o vec2list.o mat2.o \ color_mapper.o gif_image.o gifx_image.o PROGRAM = xjig all: $(PROGRAM) $(PROGRAM): $(OBJS) $(LD) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM) xjig.o: $(CXX) $(CXXFLAGS) -DPINUP_DEFAULT=$(PINUP_DEFAULT) -DJIG_DEFAULT=$(JIG_DEFAULT) -c xjig.C -o $@ clean: -rm -f core *.o $(PROGRAM) xjig.o: xjig.C objects.o: objects.C stack.o: stack.C imgbuff.o: imgbuff.C puzzle.o: puzzle.C real.o: real.C vec2.o: vec2.C vec2list.o: vec2list.C mat2.o: mat2.C color_mapper.o: color_mapper.C gif_image.o: gif_image.C gifx_image.o: gifx_image.C # ----------------------------------------------------------------------- # dependencies generated by makedepend # DO NOT DELETE color_mapper.o: color_mapper.H gif_image.o: gif_image.H gifx_image.o: global.h gifx_image.H gif_image.H color_mapper.H reset_image.H imgbuff.o: global.h imgbuff.H mat2.o: global.h mat2.h real.h vec2.h mat2_x.o: global.h vec2.h vec2list.h mat2.h real.h matrix.o: global.h matrix.h vector.h real.h matrix_x.o: global.h vec2.h vec3.h real.h matrix.h vector.h objects.o: global.h objects.H stack.H vec2.h vec2list.h mat2.h real.h objects.o: gifx_image.H gif_image.H imgbuff.H color_mapper.H puzzle.H objects.o: rotate.H puzzle.o: global.h puzzle.H objects.H stack.H vec2.h vec2list.h mat2.h real.h real.o: global.h real.h stack.o: global.h stack.H objects.H vec2.h vec2list.h mat2.h real.h stack.o: gifx_image.H gif_image.H vec2.o: global.h vec2.h vec2list.o: global.h vec2list.h mat2.h real.h vec2.h vec3.o: global.h vec3.h real.h vector.o: global.h vector.h real.h vec2.h vec3.h xjig.o: global.h objects.H stack.H vec2.h vec2list.h mat2.h real.h xjig.o: gifx_image.H gif_image.H color_mapper.H imgbuff.H puzzle.H cursor.h xjig-2.4.orig/stack.C100644 1750 1750 14627 6172765032 12673 0ustar davedave#include #include #include #include #ifndef _global_h # include "global.h" #endif #ifndef _stack_h # include "stack.H" #endif #ifndef _objects_h # include "objects.H" #endif #ifndef _gifx_image_h # include "gifx_image.H" #endif Object::Object() { next=0; } Object::~Object() { if (mystack) mystack->Remove(this); } void Object::ExposeWindowRegion( Window /*w*/, int /*x*/, int /*y*/, int /*width*/, int /*height*/ ) { } int Object::Intersects(int /*x*/,int /*y*/,int /*width*/,int /*height*/) { return 1; } int Object::IsInside(int /*x*/,int /*y*/) { return 0; } void Object::DispatchPress( XButtonEvent * /*xbutton*/ ) { mystack->Raise(this); } void Object::DispatchRelease( XButtonEvent * /*xbutton*/ ) { } void Object::DispatchMotion( XMotionEvent * /*xmotion*/ ) { } void Object::PanView( int /*offx*/, int /*offy*/ ) { } int Object::JoinExtent( int */*x1*/, int */*y1*/, int */*x2*/, int */*y2*/ ) { return 0; } int Object::GetExtent( int */*x1*/, int */*y1*/, int */*x2*/, int */*y2*/ ) { return 0; } void Object::ZoomView( int /*midx*/, int /*midy*/, int /*chg*/ ) { } // =========================================================================== ObjectStack::ObjectStack() { first=0; sel=0; last_sel=0; last_x=last_y=-1; dbmap=0; } ObjectStack::~ObjectStack() { while(first) delete first; if (dbmap) XFreePixmap(dpy,dbmap); } void ObjectStack::ExposeRegion(int /*x*/, int /*y*/, int /*width*/, int /*height*/) { } void ObjectStack::ExposeWindowRegion(Window /*w*/, int /*x*/, int /*y*/, int /*width*/, int /*height*/) { } void ObjectStack::Raise(Object *obj) { if (first==obj) { first=obj->next; // skip first object Append(obj); // add at end of queue } else { for (Object *current=first;current->next;current=current->next) { if (current->next==obj) { current->next=obj->next; // skip object in list while(current->next) current=current->next; // find end of list current->next=obj; // add at end of queue obj->next=0; // reset anchor break; } } } } void ObjectStack::Remove(Object *obj) { if (first==obj) { first=obj->next; // remove head of list } else { for (Object *current=first;current->next;current=current->next) { if (current->next==obj) { current->next=obj->next; // remove entry break; } } } obj->next=0; // disconnect object } void ObjectStack::Append(Object *obj) { if (first==0) { first=obj; // add as first element } else { Object *current; for (current=first;current->next;current=current->next); current->next=obj; // add as last element } obj->next=0; // anchor on last object obj->mystack=this; } void ObjectStack::PanView(int offx,int offy) { Object *current; for (current=first;current;current=current->next) current->PanView(offx,offy); } void ObjectStack::ZoomView(int midx,int midy, int chg) { width = width *(zoom_factor+chg)/ zoom_factor; height = height*(zoom_factor+chg)/ zoom_factor; pm->CreateData( width, height ); Object *current; for (current=first;current;current=current->next) current->ZoomView(midx,midy,chg); zoom_factor+=chg; } void ObjectStack::GetExtent( int *x1, int *y1, int *x2, int *y2 ) { Object *current; for (current=first;current;current=current->next) if (current->GetExtent( x1, y1, x2, y2 )) break; for ( ;current;current=current->next) current->JoinExtent( x1, y1, x2, y2 ); } // =================================== int ObjectStack::SelectObject( Object *current, int x, int y ) { if (last_sel==current&&x-last_x>=-1&&x-last_x<=1&&y-last_y>=-1&&y-last_y<=1) { // shortcut: same object reselected sel=current; return 1; } if (current->next && SelectObject(current->next,x,y)) return 1; switch( current->IsInside(x,y) ) { case 2: // found exact hit -> direct return sel=current; return 1; case 1: // store first close hit if (!close_sel) close_sel=current; } return 0; } void ObjectStack::DispatchPress( XButtonEvent *xbutton ) { if (!sel) { close_sel=0; if (!SelectObject(first,xbutton->x,xbutton->y)) { // when not direct hit, use close tile ... if (close_sel) sel=close_sel; } } if (sel) { // store last selection, which can be done again when on exactly // the same position (-> double/tripple clicks for rotations) last_sel=sel; last_x=xbutton->x; last_y=xbutton->y; sel->DispatchPress( xbutton ); } else last_sel=0; return; } void ObjectStack::DispatchRelease( XButtonEvent *xbutton ) { if (sel) { sel->DispatchRelease( xbutton ); if (!((xbutton->state&AnyButtonMask)&~(Button1Mask<<(xbutton->button-1)))) { sel=0; // no more buttons pressed -> cancel selection XDefineCursor( dpy, win, normal_cursor ); } } return; } void ObjectStack::DispatchMotion( XMotionEvent *xmotion ) { if (sel) { sel->DispatchMotion( xmotion ); } return; } // =========================================================================== DBObjectStack::DBObjectStack() { gc=XCreateGC(dpy,RootWindow(dpy,scr),0,0); } DBObjectStack::~DBObjectStack() { XFreeGC(dpy,gc); } void DBObjectStack::ExposeRegion(int x, int y, int width, int height) { Object *current; dbmap=XCreatePixmap(dpy,RootWindow(dpy,scr),width,height,DefaultDepth(dpy,scr)); for (current=first;current;current=current->next) { if (current->Intersects(x,y,width,height)) { current->ExposeRegion(x,y,width,height); } } XCopyArea(dpy,dbmap,win,gc,0,0,width,height,x,y); XFreePixmap(dpy,dbmap); dbmap=0; } // =========================================================================== WindowObjectStack::WindowObjectStack() { } WindowObjectStack::~WindowObjectStack() { } void WindowObjectStack::ExposeWindowRegion(Window w, int x, int y, int width, int height) { Object *current; for (current=first;current;current=current->next) { current->ExposeWindowRegion(w,x,y,width,height); } } void WindowObjectStack::DispatchPress( XButtonEvent *xbutton ) { xbutton->x=xbutton->x_root; xbutton->y=xbutton->y_root; ObjectStack::DispatchPress( xbutton ); } void WindowObjectStack::DispatchRelease( XButtonEvent *xbutton ) { xbutton->x=xbutton->x_root; xbutton->y=xbutton->y_root; ObjectStack::DispatchRelease( xbutton ); } void WindowObjectStack::DispatchMotion( XMotionEvent *xmotion ) { xmotion->x=xmotion->x_root; xmotion->y=xmotion->y_root; ObjectStack::DispatchMotion( xmotion ); } void WindowObjectStack::Raise(Object *obj) { XRaiseWindow( dpy, ((PieceObject*)obj)->swin ); } xjig-2.4.orig/stack.H100644 1750 1750 7006 6172772072 12653 0ustar davedave#ifndef _stack_h #define _stack_h /**************************************************************************** This module defines some classes to organizes the puzzle tiles on the Main functionalities: implementation of a stacking order dispatch of events down to the pieces control of the double buffering control zooming and panning The class Object will be a superclass of the puzzle tiles later on, even though the whole object hierarchie is actually contained in the object-module. ****************************************************************************/ // ========================================================================== class Object { public: Object(); virtual ~Object(); virtual void ExposeRegion( int x, int y, int width, int height ) = 0; virtual void ExposeWindowRegion( Window w, int x, int y, int width, int height ); virtual int Intersects( int x, int y, int width, int height ); virtual int IsInside( int x, int y ); virtual void DispatchPress( XButtonEvent * /*xbutton*/ ); virtual void DispatchRelease( XButtonEvent * /*xbutton*/ ); virtual void DispatchMotion( XMotionEvent * /*xmotion*/ ); virtual void PanView( int offx, int offy ); virtual void ZoomView( int midx, int midy, int chg ); virtual int JoinExtent( int *x1, int *y1, int *x2, int *y2 ); virtual int GetExtent( int *x1, int *y1, int *x2, int *y2 ); protected: class Object *next; class ObjectStack *mystack; friend class ObjectStack; friend class DBObjectStack; friend class WindowObjectStack; }; // ========================================================================== class ObjectStack { public: ObjectStack(); virtual ~ObjectStack(); virtual void ExposeRegion( int x1, int y1, int width, int height ); virtual void ExposeWindowRegion( Window w, int x1, int y1, int width, int height ); virtual void Raise( class Object *obj ); // move to top of stack virtual void Append( class Object *obj ); // add at top of stack virtual void Remove( class Object *obj ); // remove from stack virtual void DispatchPress( XButtonEvent *xbutton ); virtual void DispatchRelease( XButtonEvent *xbutton ); virtual void DispatchMotion( XMotionEvent *xmotion ); void PanView( int offx, int offy ); void ZoomView( int midx, int midy, int chg ); void GetExtent( int *x1, int *y1, int *x2, int *y2 ); Pixmap dbmap; // should actually by contained in DBObjectStack protected: virtual int SelectObject( class Object *current, int x, int y ); class Object *sel; class Object *close_sel; class Object *first; class Object *last_sel; int last_x, last_y; }; // ========================================================================== class DBObjectStack : public ObjectStack { public: DBObjectStack(); virtual ~DBObjectStack(); void ExposeRegion( int x1, int y1, int width, int height ); GC gc; protected: }; // ========================================================================== class WindowObjectStack : public ObjectStack { public: WindowObjectStack(); virtual ~WindowObjectStack(); void ExposeWindowRegion( Window w, int x1, int y1, int width, int height ); virtual void Raise( class Object *obj ); // move to top of stack void DispatchPress( XButtonEvent *xbutton ); void DispatchRelease( XButtonEvent *xbutton ); void DispatchMotion( XMotionEvent *xmotion ); protected: }; // ========================================================================== #endif xjig-2.4.orig/mat2.C100644 1750 1750 3601 6170516166 12377 0ustar davedave #ifndef _global_h # include "global.h" #endif #ifndef _mat2_h # include "mat2.h" #endif const Mat2 &Mat2::operator*=(const Mat2 &m) { Real h11=r11; Real h12=r12; Real h21=r21; Real h22=r22; r11 = h11*m.r11 + h12*m.r21; r21 = h21*m.r11 + h22*m.r21; r12 = h11*m.r12 + h12*m.r22; r22 = h21*m.r12 + h22*m.r22; tx += h11*m.tx + h12*m.ty; ty += h21*m.tx + h22*m.ty; return *this; } void Mat2::Invert(Mat2 *m) const { Real detA = r11*r22-r12*r21; m->r11 = r22/detA; m->r12 = -r12/detA; m->r21 = -r21/detA; m->r22 = r11/detA; m->tx = -m->r11*tx -m->r12*ty; m->ty = -m->r21*tx -m->r22*ty; } void Mat2::Split(Real *sh_p, Real *sx_p, Real *sy_p, Real *angle_p, Real *tx_p, Real *ty_p) const { Real cosa; // Rotation if (r21) { Real r1121 = r11/r21; cosa = r1121 / sqrt(1+r1121*r1121); *angle_p = acos(cosa); *sx_p = r11/cosa; *sy_p = (r11*r22/r21-r12)/(sin(*angle_p/180*M_PI)+r11*cosa/r21); *sh_p = (r22-cosa**sy_p)/r21; } else { if (r11) { *sx_p = r11; *angle_p = 0.0; cosa = 1.0; *sh_p = r12/r11; *sy_p = r22; } else { *sx_p = 0; *sh_p = 0; // sowieso egal Real r2212 = r22/r12; cosa = -r2212 / sqrt(1+r2212*r2212); *angle_p = acos(cosa); *sy_p = r22/cosa; } } // wenn beide Skalierungen negativ: Punktspiegelung if (*sx_p<0 && *sy_p<0) { *sx_p = *sx_p * -1; *sy_p = *sy_p * -1; if (*angle_p>0) *angle_p-=180.0; else *angle_p+=180.0; } if (fabs(*sx_p-1)EPS)?tx:0; *ty_p = (fabs(ty)>EPS)?ty:0; } // void Mat2::Print() const // { // cout << "Matrix r11, r12, tx " < #ifndef _real_h # include "real.h" #endif #ifndef _vec2_h # include "vec2.h" #endif // // Member: r11 r12 tx // r21 r22 ty // 0 0 1 // // Move: 1 0 tx Scale: sx 0 0 Rotate: cosa -sina 0 // 0 1 ty 0 sy 0 sina cosa 0 // 0 0 1 0 0 1 0 0 1 // // ShearX: 1 a 0 ShearY: 1 0 0 // 0 1 0 b 1 0 // 0 0 1 0 0 1 // // Multiplikation: C = A * B // cr11 = ar11*br11 + ar12*br21; // cr21 = ar21*br11 + ar22*br21; // cr12 = ar11*br12 + ar12*br22; // cr22 = ar21*br12 + ar22*br22; // ctx = ar11*btx + ar12*bty + atx; // cty = ar21*btx + ar22*bty + aty; // // inverse Matrix: // detA = r11*r22 - r12*r21 // // -1 r22/detA -r12/detA // A = -r21/detA r11/detA // tx = (r12*ty-r22*tx)/detA // ty = (r21*tx-r11*ty)/detA // // Punktumrechnung: // p2 = A * p1 // x2 = x1*r11 + y1*r12 + tx; // y2 = x1*r21 + y1*r22 + ty; // // -1 // p1 = A * p2; // x1 = ( x2*r22 - y2*r21)/detA - tx; // y1 = (-x2*r12 + y2*r11)/detA - ty; // // ------------------------------------------------------------------------- class Mat2 { public: // // Konstruktoren // Mat2() { r11=r22=1.0; r12=r21= tx=ty= 0.0; } Mat2( const Mat2 &m ) { r11=m.r11; r12=m.r12; r21=m.r21; r22=m.r22; tx=m.tx; ty=m.ty; } Mat2(const Real &ir11, const Real &ir12, const Real &itx, const Real &ir21, const Real &ir22, const Real &ity ) { r11=ir11; r12=ir12; r21=ir21; r22=ir22; tx=itx; ty=ity; } // // Methoden zum Anwenden einer Transformation. // Die der Transformation entsprechende Matrix wird von links!! // in die aktuelle Matrix hineinmultipliziert. // Mat2 &Reset(); Mat2 &Move(const Real &dx, const Real &dy); Mat2 &Move(const Vec2 &p); Mat2 &MoveX(const Real &dx); Mat2 &MoveY(const Real &dy); Mat2 &Scale(const Real &sx, const Real &sy); Mat2 &Scale(const Real &s); Mat2 &ScaleX(const Real &sx); Mat2 &ScaleY(const Real &sy); Mat2 &ScaleAt(const Real &px, const Real &py,const Real &sx, const Real &sy); Mat2 &ScaleAt(const Vec2 &p,const Real &sx, const Real &sy); Mat2 &ScaleAt(const Real &px, const Real &py,const Real &s); Mat2 &ScaleAt(const Vec2 &p,const Real &s); Mat2 &Rotate(const Real &a); Mat2 &RotateAt(const Real &px, const Real &py,const Real &a); Mat2 &RotateAt(const Vec2 &p,const Real &a); Mat2 &RotateDeg(const Real &a); Mat2 &RotateDegAt(const Real &px, const Real &py,const Real &a); Mat2 &RotateDegAt(const Vec2 &p,const Real &a); Mat2 &ShearX(const Real& a); Mat2 &ShearY(const Real& b); Mat2 &Shear(const Real& a, const Real& b); int IsRotated() const { return r12 || r21; } // // Zuweisungsoperator // const Mat2& operator=(const Mat2 &m) { r11=m.r11; r12=m.r12; r21=m.r21; r22=m.r22; tx=m.tx; ty=m.ty; return *this; } // // Operatoren // const Mat2 &operator*=(const Mat2 &m); Mat2 operator*(const Mat2 &m) const { Mat2 help(*this); return help*=m; } void Invert(Mat2 *m) const; Mat2 operator!() const { Mat2 m; Invert( &m ); return m; } Vec2 operator*(const Vec2 &p) const { return Vec2( r11*p.X() + r12*p.Y() + tx, r21*p.X() + r22*p.Y() + ty ); } // // Zugriff auf Koeffizienten // void Split( Real *sh, Real *sx, Real *sy, Real *angle, Real *mx, Real *my ) const; protected: Real r11, r12, tx; Real r21, r22, ty; }; inline Mat2 &Mat2::Reset() { r11=r22=1.0; r12=r21= tx=ty= 0.0; return *this; } inline Mat2 &Mat2::Move(const Real &dx, const Real &dy) { tx+=dx; ty+=dy; return *this; } inline Mat2 &Mat2::Move(const Vec2 &p) { tx+=p.X(); ty+=p.Y(); return *this; } inline Mat2 &Mat2::MoveX(const Real &dx) { tx+=dx; return *this; } inline Mat2 &Mat2::MoveY(const Real &dy) { ty+=dy; return *this; } inline Mat2 &Mat2::Scale(const Real &sx, const Real &sy) { r11*=sx; r21*=sy; r12*=sx; r22*=sy; tx*=sx; ty*=sy; return *this; } inline Mat2 &Mat2::Scale(const Real &s) { return Scale(s,s); } inline Mat2 &Mat2::ScaleX(const Real &sx) { r11*=sx; r12*=sx; tx*=sx; return *this; } inline Mat2 &Mat2::ScaleY(const Real &sy) { r21*=sy; r22*=sy; ty*=sy; return *this; } inline Mat2 &Mat2::ScaleAt(const Real &px, const Real &py,const Real &sx, const Real &sy) { return Move(-px,-py).Scale(sx,sy).Move(px,py); } inline Mat2 &Mat2::ScaleAt(const Vec2 &p,const Real &sx, const Real &sy) { return Move(-p).Scale(sx,sy).Move(p); } inline Mat2 &Mat2::ScaleAt(const Real &px, const Real &py,const Real &s) { return Move(-px,-py).Scale(s).Move(px,py); } inline Mat2 &Mat2::ScaleAt(const Vec2 &p,const Real &s) { return Move(-p).Scale(s).Move(p); } inline Mat2 &Mat2::Rotate(const Real &a) { Mat2 help(*this); r11 = r22 = cos(a); r12 = -( r21 = sin(a) ); tx = ty = 0.0; operator*=(help); return *this; } inline Mat2 &Mat2::RotateDeg(const Real &a) { return Rotate(a/Real(180/M_PI)); } inline Mat2 &Mat2::RotateAt(const Real &px, const Real &py,const Real &a) { return Move(-px,-py).Rotate(a).Move(px,py); } inline Mat2 &Mat2::RotateDegAt(const Real &px, const Real &py,const Real &a) { return Move(-px,-py).Rotate(a/Real(180/M_PI)).Move(px,py); } inline Mat2 &Mat2::RotateAt(const Vec2 &p,const Real &a) { return Move(-p).Rotate(a).Move(p); } inline Mat2 &Mat2::RotateDegAt(const Vec2 &p,const Real &a) { return Move(-p).Rotate(a/Real(180/M_PI)).Move(p); } inline Mat2 &Mat2::ShearX(const Real& a) { r11+=a*r21; r12+=a*r22; tx+=a*ty; return *this; } inline Mat2 &Mat2::ShearY(const Real& b) { r21+=b*r11; r22+=b*r12; ty+=b*tx; return *this; } inline Mat2 &Mat2::Shear(const Real& a, const Real& b) { return ShearX(a).ShearY(b); } #endif /* __Mat2_H */ xjig-2.4.orig/objects.C100644 1750 1750 66431 6175517144 13221 0ustar davedave #ifndef _global_h # include "global.h" #endif #include #include #ifndef _objects_h # include "objects.H" #endif #ifndef _gifx_image_h # include "gifx_image.H" #endif #ifndef _imgbuff_h # include "imgbuff.H" #endif #ifndef _vec2_h # include "vec2.h" #endif #ifndef _vec2list_h # include "vec2list.h" #endif #ifndef _mat2_h # include "mat2.h" #endif #ifndef _color_mapper_h # include "color_mapper.H" #endif #ifndef _puzzle_h # include "puzzle.H" #endif /****************************************************************************** PieceFrame - corner, edge and pin-data of the piece including polygon-spline Vec2List *vl RotatedFrame - position-data including window-position, upward-angle and rotated polygin spline Vec2 winpos Real windir Vec2List *tvl BitmapPiece - pixmap with mask of the rotated Piece Pixmap tilemask PixmapPiece - pixmap with Puzzle-Image of the rotated Piece Pixmap tilemap ShadowPiece - pixmap with Puzzle-Image and ShadowFrame of the rotated Piece Pixmap shadowmask Pixmap shadowmap PieceObject - object subclass to be stack-controlled DBPieceObject - double buffered moves and turns ******************************************************************************/ // . . . . + . . . . + . . . . + . . . . // . . . . . . . . . . . . . . . . . . . // . * . . . . . . . . . . . . . . . . . // . . . . . . . . . . . . . . . . . . . // . . . . . . . . . . . . . . . . . . . // . . . . + . . . . + . . . . + . . . . // . . . . . . . . . . . . . . . . . . . // . * . . . . . . . . . . . . . . . . . // . . . . . . . . . * . . * . . . . . . // . . * . . . . . . . . . . . . . . . . // . . . . * . * . . + . . . . + * . . . // . . . . . . . . . . . . . . . . . . . // . . . . . . . . . . . . . . . . . . . // . . . . . . . . . . . . . . . . . . . // . . . . . . . . . . . . . . . . . * . // . . . . + . . . . + . . . . + . . . . // . . . . . . . . . . . . . . . . . * . double PieceFrameSetup::spx[] = { 1, 2.5, 5, 7, 7, 5, 5, 6, 8,13 }; double PieceFrameSetup::spy[] = { 13,12.5,11, 8, 5, 2, 0,-2,-3,-3 }; PieceFrameSetup::PieceFrameSetup() { } PieceFrameSetup::~PieceFrameSetup() { } void PieceFrameSetup::Init( const Vec2 &tl, const Vec2 &tr, const Vec2 &br, const Vec2 &bl ) { center = (tl+tr+br+bl)/4; v[0] = tl-center; v[1] = tr-center; v[2] = br-center; v[3] = bl-center; pin[0] = pin[1] = pin[2] = pin[3] = 0; #if (0) printf( "%g %g %g %g\n", (double)tl.X(), (double)tl.Y(), (double)tr.X(), (double)tr.Y() ); printf( "center: %g %g\n", (double)center.X(), (double)center.Y() ); printf( "%g %g %g %g\n", (double)bl.X(), (double)bl.Y(), (double)br.X(), (double)br.Y() ); #endif } void PieceFrame::PositionChanged() {} void PieceFrame::DirectionChanged() {} PieceFrame::PieceFrame() { vl = 0; join_count=1; } PieceFrame::~PieceFrame() { if (vl) delete vl; } const Vec2List &PieceFrame::Init( const PieceFrameSetup &pfs ) { center=pfs.center; vl = new Vec2List(MaxSplineLen); for (int i=0;i<4;i++) { Vec2 s(pfs.v[i]); if (pfs.pin[i]) { int j; Vec2 e(pfs.v[(i+1)%4]); // end of segment Vec2 d=e-s; // edge vector Vec2 m1=s+pfs.pin[i]*d; // medium point for pin Vec2 bw=(s-m1)/24.0; // backstep vector to startpoint Vec2 fw=(e-m1)/24.0; // forward vector to endpoint Vec2 n=d/44; Vec2 o=(pfs.left[i]?n.TurnLeft():n.TurnRight()); *vl |= s; for (j=1;j<=HalfSplineLen;j++) { *vl |= m1 + pfs.spx[HalfSplineLen-j]*bw + pfs.spy[HalfSplineLen-j]*o; } for (j=0;jwindir; // check for correct page if (page!=obj->page) return 0; // check for an angle between -10 and +10 degrees if (fmod(windir_delta+380.0,360.0)>40) return 0; Vec2 v1(center - obj->center); Vec2 v2(winpos - obj->winpos); Real help=fabs(windir-obj->windir); Real mid_angle; if (help>180.0) mid_angle=fmod((windir+obj->windir+360.0)/2,360.0); else mid_angle=fmod((windir+obj->windir)/2,360.0); Vec2 erg; v2=v2.TurnAngleDeg( -mid_angle ); if (page) { erg=Vec2(v1.X()+v2.X(),v1.Y()-v2.Y()); } else erg=Vec2(v1.X()-v2.X(),v1.Y()-v2.Y()); #ifdef DEBUG v2=v2.TurnAngleDeg( mid_angle ); printf( "ImageA: %6.2f %6.2f WindowA: %6.2f %6.2f at angle: %6.2f\n", (double)center.X(), (double)center.Y(), (double)winpos.X(), (double)winpos.Y(), (double)windir ); printf( "ImageB: %6.2f %6.2f WindowB: %6.2f %6.2f at angle: %6.2f\n", (double)obj->center.X(), (double)obj->center.Y(), (double)obj->winpos.X(), (double)obj->winpos.Y(), (double)obj->windir ); printf( " %6.2f %6.2f %6.2f %6.2f\n", (double)v1.X(), (double)v1.Y(), (double)v2.X(), (double)v2.Y() ); v2=v2.TurnAngleDeg( -mid_angle ); printf( " angle: %6.2f %6.2f %6.2f\n", mid_angle, (double)v2.X(), (double)v2.Y() ); printf( " %6.2f %6.2f\n", (double)erg.X(), (double)erg.Y() ); #endif if (erg.Norm()Len()); for (int i=0;iLen();i++) { tvl->AddAt(i,Vec2( -(*vl)[i].X(), (*vl)[i].Y() )); } } tvl->TurnAngleDeg(windir); } // DoJoin: // A Joined segment in both polylines has to be found. When found // the points out of that segment are added from the second to the first // polyline, which will result into the merge of the two outlines. // // vl: +----+----+----+----+----+----+----+---- // 1 2 3 4 s j e 7 8 // obj->vl: +----+----+----+---- // 1' e i s 4' // result: +----+----+----+----+----+----+----+----+----+---- // 1 2 3 4 s 4' 1' e 7 8 // // special cases: // obj->vl: +----+----+----+---- // 1' 2' i s 4' // e int RotatedFrame::FindStartForJoin( class PieceFrame *obj ) { int i,j; for (i=0;ivl->Len();i++) { for (j=0;jLen();j++) { if (same_point(j,obj,i)) return i; } } return -1; } int RotatedFrame::DoJoin( class RotatedFrame *obj, int i, int swap ) { int j,k; for (j=0;jLen();j++) { if (same_point(j,obj,i)) { // found intersecting point: now find start and end of intersection int s,e; int sj; int ej; int c=1; for (s=1;svl->Len();s++) { int si=(i+s)%obj->vl->Len(); sj=((j-s)+vl->Len())%vl->Len(); if (!same_point(sj,obj,si)) break; c++; } s--; sj=((j-s)+vl->Len())%vl->Len(); for (e=1;evl->Len();e++) { int ei=((i-e)+obj->vl->Len())%obj->vl->Len(); ej=(j+e)%vl->Len(); if (!same_point(ej,obj,ei)) break; c++; } e--; ej=(j+e)%vl->Len(); // found start and end of intersection as in shown in diagramm // now the points have to be moved to the destination polygon DBG2( "*** Range: %d %d\n", sj, ej ); if ((sj==ej)&&(c>1)) { // // when a surrounding tile is moved onto of the inner tile, the // problem arise that the whole inner tile and the partial surrounding // tile has to be deleted. Since this usually happens the other way round: // "The hole is filled with the inner tile.", this special case is reversed // by swapping both tiles and redoing the join, in which the partial list // of the surrounding tile will be found in sj - ej // DBG0( "*** special inner case: do reverse join\n" ); Vec2 help_center=center; center=obj->center; obj->center=help_center; Vec2List *help_list=vl; vl=obj->vl; obj->vl=help_list; return DoJoin(obj,j,1); } join_count+=obj->join_count; vl->DelRange(sj,ej,&sj); k=(-e+obj->vl->Len())%obj->vl->Len(); if ( k!=s || (sj==ej&&c==1) ) { DBG1( "*** Insert at: %d -", sj ); do { DBG1( " %d", (i+k)%obj->vl->Len() ); vl->AddAt(sj+1,(*obj->vl)(i+k)+obj->center-center); k=(k-1+obj->vl->Len())%obj->vl->Len(); } while( k!=s ); DBG0( "\n" ); } else { // an inner tile was removed from the polyline and therefore // some kind of one way trail to the inner tile remained in the // polyline which should be removed with a tiny "garbage" collector. DBG1( "*** Garbage Deleted (from: %d)", vl->Len() ); for (j=0;jLen()-2;j++) { while (same_point(j,this,j+2)) { DBG1( "%d ", j ); vl->DelRange(j,j+2,&j); if (j>0) j--; } } DBG1( " (to: %d)\n", vl->Len() ); } // the new extend has to be queried to setup the center Vec2 tl, br; vl->GetExtent( &tl, &br ); Vec2 new_center( center+((tl+br)/2) ); #if (0) printf( " center: %g %g\n", center.X(), center.Y() ); printf( " from: %g %g\n", tl.X(), tl.Y() ); printf( " to: %g %g\n", br.X(), br.Y() ); printf( "new center: %g %g\n", new_center.X(), new_center.Y() ); #endif if (swap) { // this time the second objects position should be remained winpos = obj->winpos-(obj->center-new_center).ScaleX(page?-1:1).TurnAngleDeg(obj->windir); } else winpos -= (center-new_center).ScaleX(page?-1:1).TurnAngleDeg(windir); *vl += (center-new_center); center=new_center; PositionChanged(); DirectionChanged(); return 1; } } return 0; } // =========================================================================== FlipFrame::FlipFrame() { ftvl=0; itm=0; } FlipFrame::~FlipFrame() { if (ftvl) delete ftvl; if (itm) delete itm; } void FlipFrame::StartFlip( const Real &angle ) { mangle = angle; } void FlipFrame::StopFlip() { if (ftvl) delete ftvl; ftvl=0; if (itm) delete itm; itm=0; } void FlipFrame::SetFlip( const Real ¤t ) { if (ftvl) delete ftvl; if (itm) delete itm; itm = new Mat2(); // set up transformation if (page) *itm = (*itm).ScaleX( -1 ); *itm = (*itm).RotateDeg( -windir ) .Rotate( mangle ) .ScaleX( current ) .Rotate( -mangle ); ftvl = new Vec2List(RotatedFrame::GetPolyLine(),*itm); *itm = !*itm; // reverse transformation for texture-mapping DirectionChanged(); } Vec2List &FlipFrame::GetTPolyLine() { if (!ftvl) return *tvl; else return *ftvl; } // =========================================================================== GC BitmapPiece::gcb = 0; BitmapPiece::BitmapPiece() { tilemask = 0; } BitmapPiece::~BitmapPiece() { DropBitmap(); } void BitmapPiece::DropBitmap() { if (tilemask) { XFreePixmap(dpy,tilemask); tilemask=0; } } void BitmapPiece::PositionChanged() { winx = XPix(winpos.X())-offx; winy = YPix(winpos.Y())-offy; } void BitmapPiece::DirectionChanged() { DropBitmap(); FlipFrame::DirectionChanged(); Vec2 tl,br; int x1,y1,x2,y2; const Vec2List &poly( GetTPolyLine() ); poly.GetExtent( &tl, &br ); x1 = XPix(tl.X()); y1 = YPix(tl.Y()); x2 = XPix(br.X()); y2 = YPix(br.Y()); offx = -x1; offy = -y1; winx = XPix(winpos.X())-offx; winy = YPix(winpos.Y())-offy; width = x2-x1+1; height = y2-y1+1; #if (0) printf( "%g %g (%d %d)\n", (double)tl.X(), (double)tl.Y(), offx, offy ); printf( "center: %g %g\n", (double)center.X(), (double)center.Y() ); printf( " %g %g\n", (double)br.X(), (double)br.Y() ); #endif tilemask=XCreatePixmap(dpy,RootWindow(dpy,scr),width,height,1); if (!gcb) gcb=XCreateGC(dpy,tilemask,0,0); XSetForeground(dpy,gcb,0); // clear the new bitmap XFillRectangle(dpy,tilemask,gcb,0,0,width,height); XSetForeground(dpy,gcb,1); // draw the polyline XPoint xpts[MaxSplineLen]; XPoint *xpts_p; if ((unsigned)poly.Len()>(sizeof(xpts)/sizeof(XPoint))) { xpts_p=new XPoint[poly.Len()]; // create buffer when necessary } else xpts_p=xpts; for (int i=0;iIsTwinPixmap()) wcenter=Vec2( center.X(), pm->XHeight()+center.Y() ); else wcenter=center; XCopyArea(dpy,pm->GetPixmap(),tilemap,gcp, XPix(wcenter.X())-offx, YPix(wcenter.Y())-offy, width, height, 0, 0 ); } else { switch(texture_mode) { case 1: CreateTilemap8(); break; case 2: CreateTilemap16(); break; case 3: CreateTilemap32(); break; } } } void PixmapPiece::Redraw() { // printf( "winpos: %g %g\n", (double)winpos.X(), (double)winpos.Y() ); // printf( "offx: %d %d\n", offx, offy ); XSetClipMask(dpy,gc,GetBitmap()); XSetClipOrigin(dpy,gc,winx,winy); GetPixmap(); XCopyArea(dpy,tilemap,win,gc, 0, 0, width, height, winx, winy ); } // =========================================================================== ShadowedPiece::ShadowedPiece() { shadowmap = 0; if (!gcp) gcp=XCreateGC(dpy,RootWindow(dpy,scr),0,0); } ShadowedPiece::~ShadowedPiece() { DropPixmap(); } void ShadowedPiece::DropPixmap() { if (shadowmap) { XFreePixmap(dpy,shadowmap); shadowmap=0; XFreePixmap(dpy,shadowmask); } } void ShadowedPiece::DirectionChanged() { int x; DropPixmap(); PixmapPiece::DirectionChanged(); swidth = width + 2*ShadowSize(); sheight = height + 2*ShadowSize(); // create mask of the shadowed tile shadowmask=XCreatePixmap(dpy,RootWindow(dpy,scr),swidth,sheight,1); XSetForeground(dpy,gcb,0); XFillRectangle(dpy,shadowmask,gcb,0,0,swidth,sheight); XSetFunction(dpy,gcb,GXor); for (x=0;x<=2*ShadowSize();x++) { XCopyArea(dpy,tilemask,shadowmask,gcb,0,0,width,height,x,x); } XSetFunction(dpy,gcb,GXcopy); // create the tile shadowmap=XCreatePixmap(dpy,RootWindow(dpy,scr),swidth,sheight,DefaultDepth(dpy,scr)); XSetForeground(dpy,gc,WhitePixel(dpy,scr)); XSetClipMask(dpy,gc,tilemask); for (x=0;x=swidth || y >=sheight) return 0; help_image=XGetImage(dpy,shadowmask,x,y,1,1,1,XYPixmap); unsigned long erg=XGetPixel(help_image,0,0); XDestroyImage(help_image); return (int)erg; } // =========================================================================== WindowPiece::WindowPiece() { swin=0; } WindowPiece::~WindowPiece() { if (swin) XDestroyWindow( dpy, swin ); } void WindowPiece::CreateWindow() { XSetWindowAttributes attrib; swin=XCreateSimpleWindow(dpy,RootWindow(dpy,scr), winx,winy,swidth,sheight,0,WhitePixel(dpy,scr), port->AllocNamedColor( "grey50" ) ); attrib.bit_gravity=StaticGravity; attrib.override_redirect = True; XChangeWindowAttributes( dpy, swin, CWBitGravity|CWOverrideRedirect, &attrib ); XSelectInput(dpy,swin, ExposureMask|KeyPressMask|EnterWindowMask|ButtonPressMask|ButtonReleaseMask|ButtonMotionMask); } void WindowPiece::PositionChanged() { ShadowedPiece::PositionChanged(); if (shapes) { if (swin) XMoveWindow( dpy, swin, winx, winy ); } } void WindowPiece::DirectionChanged() { ShadowedPiece::DirectionChanged(); if (shapes) { if (!swin) { CreateWindow(); XShapeCombineMask(dpy,swin,0 /*Bounding*/,0,0,shadowmask,0 /*Set*/); XMapRaised(dpy,swin); } else { XMoveResizeWindow(dpy,swin,winx,winy,swidth,sheight); XShapeCombineMask(dpy,swin,0 /* Bounding */,0,0,shadowmask,0 /* Set */); } Redraw(); } } void WindowPiece::Redraw() { XSetClipMask(dpy,gc,shadowmask); XSetClipOrigin(dpy,gc,0,0); XCopyArea(dpy,shadowmap,swin,gc, 0, 0, swidth, sheight, 0, 0 ); } // =========================================================================== PieceObject::PieceObject() { } PieceObject::~PieceObject() { } int PieceObject::Intersects(int x,int y,int w,int h) { if ( (x>winx+swidth) || (winx>x+w) || (y>winy+sheight) || (winy>y+h) ) return 0; else return 1; } int PieceObject::IsInside(int x,int y) { if ((x>=winx)&&(x=winy)&&(ydbmap,gc, 0, 0, swidth, sheight, winx-x, winy-y ); } void PieceObject::ExposeWindowRegion(Window w,int /*x*/,int /*y*/,int /*width*/,int /*height*/) { if (w==swin) { XSetClipMask(dpy,gc,shadowmask); XSetClipOrigin(dpy,gc,0,0); XCopyArea(dpy,shadowmap,swin,gc, 0, 0, swidth, sheight, 0, 0 ); } } void PieceObject::PanView( int ox, int oy ) { winpos-=Vec2(ox,oy); PositionChanged(); } void PieceObject::ZoomView( int midx, int midy, int chg ) { double factor=((double)(zoom_factor+chg))/zoom_factor; center = center * factor; *vl = *vl * factor; winpos = (winpos-Vec2(midx,midy)) * factor + Vec2(midx,midy); PositionChanged(); DirectionChanged(); } // =========================================================================== int DBPieceObject::x1; int DBPieceObject::y1; int DBPieceObject::x2; int DBPieceObject::y2; DBPieceObject::DBPieceObject() { } DBPieceObject::~DBPieceObject() { } void DBPieceObject::TurnOver( const Real &d ) { XDefineCursor( dpy, win, no_cursor ); XFlush(dpy); Real a; Real start_windir=windir; a=fmod(d-start_windir+360,360); if (a>180.0) a=a-360.0; if (join_count<=maxturntiles) { double turnstart=GetCurrentTime()-0.1; double turntime=turntimebase+join_count*turntimedelta; double loop; for ( loop=0.1; loop<0.9; loop=(GetCurrentTime()-turnstart)/turntime) { StoreExtent(); SetDir( start_windir+loop*a ); UpdateExtent(); XSync(dpy,0); } } StoreExtent(); SetDir(d); UpdateExtent(); } void DBPieceObject::FlipOver( const Vec2 &pos ) { XDefineCursor( dpy, win, no_cursor ); XFlush(dpy); Vec2 wpos=pos; // button position after probable adjustment Real wa=winpos.AngleDeg(pos); // angle to button position if (fmod(windir+5,90)<10) { // close to straight -> adjusted flip // Probably round position for exact flips // int quart=(int)(fmod(wa+22,360)/45)&3; int quart=(int)(fmod(wa+45,360)/45)&2; switch(quart) { case 0: { wpos=Vec2( pos.X(), winpos.Y() ); // horizontal flip break; } case 1: { Vec2 erg; // diagonal flip 1 (pos-winpos).Split( Vec2(1,-1), &erg ); // project to diagonal wpos=winpos+erg; break; } case 2: { wpos=Vec2( winpos.X(), pos.Y() ); // vertival flip break; } case 3: { Vec2 erg; // diagonal flip 2 (pos-winpos).Split( Vec2(1,1), &erg ); // project to diagonal wpos=winpos+erg; break; } } wa=winpos.AngleDeg(wpos); // angle to (adjusted position) } Vec2 mdir=wpos-winpos; // move distance to center of flip Vec2 newpos=mdir+wpos; // destination on other side of the flip Real a=wa+90; // angle of mirror Real newdir=a-(windir-a)+180; // new windir after the flip DBG1( "*** Mirror Angle: %g\n", (double)a ); DBG2( "*** Windir: %g -> New Angle: %g\n", (double)wa, (double)newdir ); if (join_count<=maxfliptiles) { // do tiny animation, if there are less than 5 tiles combined Real flipstart=GetCurrentTime(); Real loop; // current state of the flip double fliptime=fliptimebase+join_count*fliptimedelta; StartFlip( Vec2Zero.AngleRadial(mdir) );// start flipping up for (loop=0.9;loop>=flipsave;loop=1.0-(GetCurrentTime()-flipstart)/fliptime) { StoreExtent(); SetPos( wpos-loop*mdir ); SetFlip( loop ); UpdateExtent(); XSync(dpy,0); } StoreExtent(); // swap to other side FlipPage(); SetDir(newdir); loop=flipsave; // first frame on back side flipstart=GetCurrentTime(); StartFlip( Vec2Zero.AngleRadial(wpos-newpos) ); SetPos( wpos+loop*mdir ); SetFlip(loop); UpdateExtent(); XSync(dpy,0); loop=flipsave+(GetCurrentTime()-flipstart)/fliptime; for (;loop<1.0-0.1;loop=flipsave+(GetCurrentTime()-flipstart)/fliptime) { StoreExtent(); SetPos( wpos+loop*mdir ); SetFlip( loop ); UpdateExtent(); XSync(dpy,0); } StoreExtent(); // last frame on back side SetPos(newpos); StopFlip(); DirectionChanged(); // trigger for a last update UpdateExtent(); } else { StoreExtent(); // just flip and show FlipPage(); SetPos(newpos); SetDir(newdir); UpdateExtent(); } } void DBPieceObject::StoreExtent() { x1 = winx; // store old frame y1 = winy; x2 = x1+swidth; y2 = y1+sheight; } int DBPieceObject::JoinExtent( int *xx1, int *yy1, int *xx2, int *yy2 ) { if (winx<*xx1) *xx1 = winx; if (winy<*yy1) *yy1 = winy; if (winx+swidth>*xx2) *xx2 = winx+swidth; if (winy+sheight>*yy2) *yy2 = winy+sheight; return 1; } int DBPieceObject::GetExtent( int *xx1, int *yy1, int *xx2, int *yy2 ) { *xx1 = winx; *yy1 = winy; *xx2 = winx+swidth; *yy2 = winy+sheight; return 1; } void DBPieceObject::JoinExtent() { if (winxx2) x2=winx+swidth; if (winyy2) y2=winy+sheight; } void DBPieceObject::UpdateExtent() { JoinExtent(); mystack->ExposeRegion(x1,y1,x2-x1,y2-y1); } // =========================================================================== int MoveablePiece::turnflag; // flag about direction of turn Time MoveablePiece::start_time; // event time of button press Real MoveablePiece::start_angle; // angle at the start of turn Vec2 MoveablePiece::start; Vec2 MoveablePiece::poffset; // offset of pointer from center Real MoveablePiece::poffset_len; // length of offset of pointer from center MoveablePiece::MoveablePiece() { } MoveablePiece::~MoveablePiece() { } void MoveablePiece::DispatchPress( XButtonEvent * xbutton ) { if (xbutton->state&ControlMask) { // printf( "doing the flip ...\n" ); mystack->Raise(this); FlipOver( Vec2(xbutton->x,xbutton->y) ); start_time=0; } else { start_time=xbutton->time; } start_angle=GetDir(); if (xbutton->state&AnyButtonMask) { // there is already a button pressed ... if (xbutton->button==Button1) { // second button in addition to middle button -> turn around center turnflag=2*(xbutton->button-Button1-1); } else { // start non-rotating motion on multiple press turnflag=0; } } else { // first button - start normal drag mystack->Raise(this); start=Vec2( xbutton->x, xbutton->y ); poffset=(start-winpos); poffset_len=poffset.Norm(); // when too close to the center of the tile - move it off a bit ... while (poffset_len<2) { // printf( "*** very close hit - moving start\n" ); start+=Vec2(1,1); poffset=(start-winpos); poffset_len=poffset.Norm(); } turnflag=xbutton->button-Button1-1; if (poffset_lenx,xmotion->y); Vec2 new_offset=newpos-(start-poffset); if (fabs(new_offset.X())+fabs(new_offset.Y())<2) { DBG0( "#### skipping event near center of tile\n" ); return; } switch (turnflag) { case 2: case -2: { // new style for turning around center Real a1=Vec2Zero.AngleDeg(poffset); Real a2=Vec2Zero.AngleDeg(new_offset); poffset=new_offset; MoveTurn(newpos-poffset,GetDir()-a1+a2); break; } case -1: { // new style for pulling corners new_offset=(new_offset).Norm1()*poffset_len; Real a1=Vec2Zero.AngleDeg(poffset); Real a2=Vec2Zero.AngleDeg(new_offset); poffset=new_offset; MoveTurn(newpos-poffset,GetDir()-a1+a2); break; } case 1: default: Move( newpos-poffset ); break; } start=newpos; } void MoveablePiece::DispatchRelease( XButtonEvent * xbutton ) { if (xbutton->button!=Button2&&(xbutton->button==Button1||!(xbutton->state&Button1Mask))) { if (xbutton->time-start_time<150) { switch(xbutton->button) { case Button1: TurnOver(start_angle+90.0); break; case Button3: TurnOver(start_angle-90.0); break; } } turnflag=0; } else if (xbutton->time-start_time<150&&xbutton->button==Button2&&!(xbutton->state&~Button2Mask)) { FlipOver(Vec2(xbutton->x,xbutton->y)); } else if (xbutton->state&Button1Mask) turnflag=-1; // restart rotatable drag if (!((xbutton->state&AnyButtonMask)&~(Button1Mask<<(xbutton->button-1)))) { XDefineCursor( dpy, win, idle_cursor ); XFlush(dpy); // no more buttons pressed -> check against other pieces if (p->CheckForJoin( (Piece*)this )) { /* don't use THIS in this case since it's already deleted !!! */ } else { AdjustDirection(); } } else XDefineCursor( dpy, win, (turnflag)?pull_cursor:move_cursor ); } xjig-2.4.orig/objects.H100644 1750 1750 22734 6175517354 13227 0ustar davedave#ifndef _objects_h #define _objects_h /****************************************************************************** The functionality of the puzzle tiles was created and tested step by step by implementing a linear class with each subclass adding a few special features to the full object. PieceFrame - corner, edge and pin-data of the piece including polygon-spline Vec2List *vl TwinPieceFrame - intermediate class to store the current page of the tile RotatedFrame - position-data including window-position, upward-angle and rotated polygin spline Vec2 winpos Real windir Vec2List *tvl FlipFrame - intermediate class to control the flip animation with the help of a transformation matrix Mat2 *itm Vec2List *ftvl BitmapPiece - pixmap with mask of the rotated Piece Pixmap tilemask PixmapPiece - pixmap with Puzzle-Image of the rotated Piece Pixmap tilemap ShadowPiece - pixmap with Puzzle-Image and ShadowFrame of the rotated Piece Pixmap shadowmask Pixmap shadowmap WindowPiece - class to control creation of local windows for each tile Window swin PieceObject - object subclass to be stack-controlled DBPieceObject - double buffered moves and turns ******************************************************************************/ #ifndef _stack_h # include "stack.H" #endif #ifndef _vec2_h # include "vec2.h" #endif #ifndef _vec2list_h # include "vec2list.h" #endif #ifndef _mat2_h # include "mat2.h" #endif // =========================================================================== // ************** // * PieceFrame * // ************** // // The PieceFrame class containes the information about the boundary corners of // an image in the original puzzle picture. Therefore the 4 corners are stored // in that class (messured relative to the center of the object). // Additionally the information, how the splines of the 4 pins are located, // is stored in that class. // // The data is set up by Puzzle::Init // // All the edge information is finally combined into a point-list of a // polygon, that surrounds the whole tile. class PieceFrameSetup { public: PieceFrameSetup(); virtual ~PieceFrameSetup(); void Init( const Vec2 &tl, const Vec2 &tr, const Vec2 &br, const Vec2 &bl ); void SetPin( int i, int l, const Real &pd ) { left[i]=l; pin[i]=pd; } protected: #define HalfSplineLen 10 #define MaxSplineLen (8*HalfSplineLen+5) protected: Vec2 v[4]; // coordinates of corners (offset to center) char left[4]; // flag, wether the pin is left ro right Real pin[4]; // offset of pin (-1 .. 1) Vec2 center; // center of piece in origin static double spx[HalfSplineLen]; // Spline-Position for any Pin static double spy[HalfSplineLen]; friend class PieceFrame; }; // =========================================================================== class PieceFrame{ public: PieceFrame(); virtual ~PieceFrame(); const Vec2List &Init( const PieceFrameSetup &pfs ); const Vec2List &GetPolyLine() { return *vl; } const Vec2 &Center() { return center; } virtual void PositionChanged(); virtual void DirectionChanged(); protected: Vec2 center; Vec2List *vl; // non-rotated polyline with pins and corners int same_point(int j,class PieceFrame *obj,int i) { Vec2 dist( ((*obj->vl)[i]+obj->center) - ((*vl)[j]+center) ); return (fabs(dist.X())17 && help<23 ||(join_count>minadjustcount && help<40 && help!=20.0)) { SetDir(windir+20-help); return 1; } else return 0; } Real GetDir() { return windir; } void Redraw(); virtual void PositionChanged(); virtual void DirectionChanged(); Vec2List &GetTPolyLine() { return *tvl; } int CheckForJoin( class RotatedFrame *obj ); int FindStartForJoin( class PieceFrame *obj ); int DoJoin( class RotatedFrame *obj, int i, int swap=0 ); protected: Vec2 winpos; // Window-Position Real windir; // upward angle of tile; Vec2List *tvl; // pointlist of turned points }; // =========================================================================== class FlipFrame : public RotatedFrame { public: FlipFrame(); virtual ~FlipFrame(); Vec2List &GetTPolyLine(); void StartFlip( const Real &angle ); void SetFlip( const Real ¤t ); void StopFlip(); protected: Real mangle; // flip angle Vec2List *ftvl; Mat2 *itm; }; // =========================================================================== class BitmapPiece : public FlipFrame { public: BitmapPiece(); virtual ~BitmapPiece(); void DropBitmap(); virtual void PositionChanged(); virtual void DirectionChanged(); Pixmap GetBitmap() { return tilemask; } void Redraw(); protected: int winx, winy; // TopLeft in window int offx, offy; // TopLeft corner-offset from center int width, height; // size of bitmap Pixmap tilemask; // the bitmap itself static GC gcb; // GC to draw in Bitmaps friend class DBPieceObject; }; // =========================================================================== class PixmapPiece : public BitmapPiece { public: PixmapPiece(); virtual ~PixmapPiece(); void DropPixmap(); virtual void DirectionChanged(); Pixmap GetPixmap() { return tilemap; } void Redraw(); protected: void CreateTilemap8(); void CreateTilemap16(); void CreateTilemap32(); Pixmap tilemap; static GC gcp; }; // =========================================================================== class ShadowedPiece : public PixmapPiece { public: ShadowedPiece(); virtual ~ShadowedPiece(); void DropPixmap(); virtual void DirectionChanged(); Pixmap GetPixmap() { return shadowmap; } void Redraw(); int ShadowSize() { return shadow_size; } int IsInside( int x, int y ); protected: Pixmap shadowmask; Pixmap shadowmap; int swidth,sheight; friend class DBPieceObject; }; // =========================================================================== class WindowPiece : public ShadowedPiece { public: WindowPiece(); virtual ~WindowPiece(); virtual void PositionChanged(); virtual void DirectionChanged(); void Redraw(); protected: void CreateWindow(); Window swin; friend class WindowObjectStack; }; // =========================================================================== class PieceObject : public WindowPiece, public Object { public: PieceObject(); virtual ~PieceObject(); virtual int Intersects(int x,int y,int width,int height); virtual int IsInside(int x,int y); virtual void ExposeRegion(int x,int y,int width,int height); virtual void ExposeWindowRegion(Window w, int x,int y,int width,int height); virtual void PanView( int offx, int offy ); virtual void ZoomView( int midx, int midy, int chg ); private: }; // =========================================================================== class DBPieceObject : public PieceObject { public: DBPieceObject(); virtual ~DBPieceObject(); void Move( const Vec2 &pos ) { StoreExtent(); SetPos(pos); UpdateExtent(); }; void MoveTurn( const Vec2 &pos, const Real &d ) { StoreExtent(); SetPos(pos); SetDir(d); UpdateExtent(); }; void Turn( const Real &d ) { StoreExtent(); SetDir(d); UpdateExtent(); }; void FlipOver( const Vec2 &pos ); // animated flip void TurnOver( const Real &d ); // animated turn void AdjustDirection() { StoreExtent(); if (PieceObject::AdjustDir()) UpdateExtent(); }; int JoinExtent( int *x1, int *y1, int *x2, int *y2 ); int GetExtent( int *x1, int *y1, int *x2, int *y2 ); void StoreExtent(); void JoinExtent(); void UpdateExtent(); private: static int x1,y1,x2,y2; }; // =========================================================================== class MoveablePiece : public DBPieceObject { public: MoveablePiece(); virtual ~MoveablePiece(); virtual void DispatchPress( XButtonEvent * /*xbutton*/ ); virtual void DispatchRelease( XButtonEvent * /*xbutton*/ ); virtual void DispatchMotion( XMotionEvent * /*xmotion*/ ); private: static int turnflag; // -1 = left, 0 = no turn, 1 = right // -2/2 = around center static Time start_time; static Real start_angle; static Vec2 start; static Vec2 poffset; static Real poffset_len; }; // =========================================================================== class Piece : public MoveablePiece { }; #endif xjig-2.4.orig/imgbuff.H100644 1750 1750 1562 6173112420 13150 0ustar davedave #ifndef _imgbuff_h #define _imgbuff_h #ifdef USE_MIT_SHM #include #include #include #endif class ImageBuffer { public: ImageBuffer(); ~ImageBuffer(); XImage *Init(int w, int h, int bpp8); XImage *GetXImage() { return ximage; } void PutImage(Display *dpy,Drawable d,GC gc,int src_x, int src_y, int dest_x, int dest_y, unsigned int w, unsigned int h) { #ifdef USE_MIT_SHM if (shm) { XShmPutImage(dpy,d,gc,ximage,src_x,src_y,dest_x,dest_y,w,h,False); XSync(dpy,0); } else #endif XPutImage(dpy,d,gc,ximage,src_x,src_y,dest_x,dest_y,w,h); } private: void AllocData(int w,int h,int bpp8); void FreeData(); XImage *ximage; int width, height; #ifdef USE_MIT_SHM int shm; // flag, if shared memory is in use XShmSegmentInfo shminfo; // shm information #endif }; #endif xjig-2.4.orig/imgbuff.C100644 1750 1750 3130 6173112356 13144 0ustar davedave #ifndef _global_h # include "global.h" #endif #ifndef _imgbuff_h # include "imgbuff.H" #endif ImageBuffer::ImageBuffer() { ximage=0; width=0; height=0; #ifdef USE_MIT_SHM int major,minor; Bool pmaps; shm=(shared)?XShmQueryVersion(dpy,&major,&minor,&pmaps):0; if (shm&&verbose) { printf( "--- using shared memory extension V%d.%d %s\n", major, minor, ((pmaps)?"(shared pixmaps supported)":"") ); } #endif } ImageBuffer::~ImageBuffer() { FreeData(); } void ImageBuffer::FreeData() { if (ximage) { #ifdef USE_MIT_SHM if (shm) { XShmDetach(dpy,&shminfo); XDestroyImage(ximage); shmdt(shminfo.shmaddr); shmctl(shminfo.shmid, IPC_RMID, 0 ); } else #endif { free( ximage->data ); ximage->data = 0L; XDestroyImage(ximage); } ximage=0; } } void ImageBuffer::AllocData(int w, int h, int bpp8) { FreeData(); width = w; height = h; #ifdef USE_MIT_SHM if (shm) { ximage = XShmCreateImage(dpy, DefaultVisual(dpy,scr), DefaultDepth(dpy,scr), ZPixmap, NULL, &shminfo, width, height ); shminfo.shmid = shmget(IPC_PRIVATE, ximage->bytes_per_line * ximage->height, IPC_CREAT|0777); shminfo.shmaddr = ximage->data = (char*)shmat(shminfo.shmid,0,0); shminfo.readOnly = False; XShmAttach(dpy,&shminfo); } else #endif { char *data=(char*)malloc(width*height*bpp8); ximage = XCreateImage(dpy, DefaultVisual(dpy,scr), DefaultDepth(dpy,scr), ZPixmap, 0, data, width, height, (8*bpp8), width*bpp8 ); } } XImage *ImageBuffer::Init(int w,int h,int bpp8) { // w+=10; h+=10; if (w>width||h>height) { FreeData(); AllocData(w,h,bpp8); } return ximage; } xjig-2.4.orig/puzzle.H100644 1750 1750 2322 6172777671 13105 0ustar davedave#ifndef _puzzle_h #define _puzzle_h #ifndef _vec2_h # include "vec2.h" #endif #ifndef _object_h // to get Piece # include "objects.H" #endif // // Class to create a grid, which should be the frame for the puzzle-pieces // class Grid { public: Grid(int w,int h); ~Grid(); void Init(int maxx, int maxy); void Reset( int x, int y ); void Randomize(int percent); Vec2 &P(int x,int y) { return p[x+width*y]; } const Real &X(int x,int y) { return p[x+width*y].X(); } const Real &Y(int x,int y) { return p[x+width*y].Y(); } int Width() { return width; } int Height() { return height; } private: int width, height; int max_width, max_height; Vec2 *p; }; class Puzzle { public: Puzzle(); ~Puzzle(); Piece &P(int x,int y) { return *(p[x+width*y]); } void Init(int img_width, int img_height, int dx, int dy, const char *sfx ); int CheckForJoin( Piece *pi, int depth=0 ); void DropTile( int x, int y ) { DropTile(x+y*width); } void DropTile( int i ) { delete p[i]; p[i]=0; tiles_left--; } void Redraw(); void Rotation(); int Finished() { return (tiles_left<=1); } private: int width,height; int tiles_left; Piece **p; Grid *g; }; #endif xjig-2.4.orig/puzzle.C100644 1750 1750 13424 6175517167 13120 0ustar davedave#ifndef _global_h # include "global.h" #endif #ifndef _puzzle_h # include "puzzle.H" #endif Grid::Grid(int w, int h) { width = w; height = h; p = new Vec2[width*height]; } Grid::~Grid() { delete [] p; } void Grid::Reset(int x, int y) { P(x,y) = Vec2( x*max_width/(width-1), y*max_height/(height-1) ); } void Grid::Init(int maxx, int maxy) { int x,y; max_width = maxx; max_height = maxy; for (x=0;xInit(img_width,img_height); g->Randomize(distortion); if (sfx) { int dir,len; const char *sfx_p=sfx; while( *sfx_p ) { if (sscanf( sfx_p, "%02x%02x%01x%01x", &x, &y, &len, &dir )!=4) { fprintf( stderr, "*** image error in extension 0x12\n" ); exit(0); } g->Reset(x,y); while( len-- ) { switch(dir) { case 0: x++; break; case 1: y++; break; case 2: x--; break; case 3: y--; break; } g->Reset(x,y); } sfx_p+=6; } } // create and initialize setup-structures for all pieces pfs = new PieceFrameSetup[width*height]; pos = new Vec2[width*height]; // setup corner information for (x=0;xP(x,y),g->P(x+1,y),g->P(x+1,y+1),g->P(x,y+1)); pos[x+width*y]=g->P(x,y)+Vec2(offx*(x+1)+img_width/dx/2,offy*(y+1)+img_height/dy/2); } } // setup pin information for (x=0;x=0) { int row=y; int col=x; // query the offset of the center from the grid edge in the original piece Vec2 org_offset(P(x,y).Center()-Vec2(x*img_width/width,y*img_height/height)); // compute the piece edge in the 'straight' position Vec2 new_pos( col*img_width/width+col*straight_setup, row*img_height/height+row*straight_setup ); P(x,y).SetPos( new_pos+org_offset ); } else { P(x,y).SetPos(pos[x+y*width]); } if (shuffle&1) P(x,y).SetDir( ((rand()%(int)(maxang*2))-maxang) + (rand()%4)*90 ); else P(x,y).SetDir(angle*(x+y)); if (side_lock<0) { if (rand()&2) P(x,y).FlipPage(); } else { if (side_lock==1) P(x,y).FlipPage(); } stk->Append( &P(x,y) ); } } delete [] pos; delete [] pfs; #undef PFS } void Puzzle::Redraw() { for (int i=0;iRedraw(); } int Puzzle::CheckForJoin( Piece *pi, int depth ) { int i,j,s; for (i=0;iCheckForJoin(pi)) { if ((s=p[i]->FindStartForJoin(pi))>=0) { // start double buffering p[i]->StoreExtent(); pi->JoinExtent(); p[i]->DoJoin(pi,s,(depth>0)?((p[i]->join_count>=pi->join_count)?0:1):0); // The part was join, so it can be deleted ... for (j=width*height-1;j>=0;j--) { if (p[j]==pi) break; } if (j>=0) DropTile(j); p[i]->UpdateExtent(); if (depthRaise(&P(x,y)); Vec2 dir((rand()%7)-3,(rand()%7)-3); for (int j=0;j<18;j++) { P(x,y).MoveTurn(P(x,y).GetPos()+dir,P(x,y).GetDir()+5.0); if (quit) return; } } #endif } xjig-2.4.orig/INSTALL100644 1750 1750 2305 6175450515 12461 0ustar davedave Making the game can be done with the supplied Makefiles, or with the Imakefile, by using: xmkmf make depend make You should probably check the comments comments at the top of the Imakefile for setting additional parameters. Have a look at the man-page or xjig.cat for further instructions on the usage. KNOWN PROBLEMS: - There are problems with the optimize option in some gcc version (e.g. 2.7.0). If the compilation runs fine, but nothing happens on the screen, this might be the problem and you should re-compile it non-optimized. - The game wasn't tested on 64bit machines yet. Since the texture-mapping routines are very low level C-functions, there might be hidden bugs depending on the underlying datatypes of the system. Comments are welcome. Have fun. __ __ __ __ __ __ _ / / / /__ / /___ ___ __ __/ /_ / / / /___ ___ ____ (_)___ _ / /_/ / _ \/ / __ `__ \/ / / / __/ / /_/ / __ \/ _ \/ __ \/ / __ `/ / __ / __/ / / / / / / /_/ / /_ / __ / /_/ / __/ / / / / /_/ / _ /_/ /_/\___/_/_/ /_/ /_/\__,_/\__/ /_/ /_/\____/\___/_/ /_/_/\__, / /__________________________________e-mail: Helmut.Hoenig@hub.de______/