Model of memory linking through memory allocation (Kastellakis et al. 2016)

 Download zip file 
Help downloading and running models
Accession:206249
Here, we present a simplified, biophysically inspired network model that incorporates multiple plasticity processes and explains linking of information at three different levels: (a) learning of a single associative memory (b) rescuing of a weak memory when paired with a strong one and (c) linking of multiple memories across time. By dissecting synaptic from intrinsic plasticity and neuron-wide from dendritically restricted protein capture, the model reveals a simple, unifying principle: Linked memories share synaptic clusters within the dendrites of overlapping populations of neurons
Reference:
1 . Kastellakis G, Silva AJ, Poirazi P (2016) Linking Memories across Time via Neuronal and Dendritic Overlaps in Model Neurons with Active Dendrites. Cell Rep 17:1491-1504 [PubMed]
Citations  Citation Browser
Model Information (Click on a link to find other models with that property)
Model Type: Realistic Network;
Brain Region(s)/Organism:
Cell Type(s): Abstract integrate-and-fire leaky neuron with dendritic subunits;
Channel(s):
Gap Junctions:
Receptor(s):
Gene(s):
Transmitter(s):
Simulation Environment: C or C++ program; C or C++ program (web link to model);
Model Concept(s): Active Dendrites;
Implementer(s): Kastellakis, George [gkastel at gmail.com];
/
stdmodel
distributionPlot
exportfig
figs
mtrand
README
allgraphs.m
allrun.m
an_brtest.m
an_stats.m
anmulti.py
ansims.py
barwitherr.m *
btagstats.m *
CImg.h *
constructs.cpp
constructs.h
defaults.m
dir2.m *
getspikedata.m *
getsynstate.m *
getsynstate2.m *
graphs.m *
hist_percents.m *
hist_with_errs.m *
interact.m *
intexp_constructs.cpp
job_sims.sh
kurtos.m *
lamodel.cpp
LICENSE *
make_graphs.m *
Makefile *
matlab.mat *
mtest.py
mtrand.cpp *
mtrand.h *
multi.py
multistats.m *
nextplot.m *
pairstrong.m *
repeated.m *
rotateXLabels.m *
run_1.sh
run_2strong.sh
run_2weak.sh
run_3.sh
run_all.sh
run_brov.sh
run_brtest.sh
run_btag.sh
run_dir.sh
run_ep.sh
run_gp.sh
run_gp2.sh
run_mult.sh
run_Nsparse.sh
run_pairstrong.sh
run_rep.sh
run_sims.sh
run_sparse.sh
run_sparseS2.sh
runloc.sh
runmany.sh
S2sparse.m *
savefig.m *
scratch.m *
sensitivity.m *
stats.m *
stats.py *
stderr.m *
strong2.m *
strongstrong.m *
submit_lamodel.sh *
three.m *
trevrolls.m *
vis.py *
weastrong.m *
wxglmodel *
wxglmodel.cpp *
wxglmodel.h *
wxmodel.cpp *
wxmodel.h *
                            
/*
 #
 #  File            : CImg.h
 #                    ( C++ header file )
 #
 #  Description     : The C++ Template Image Processing Toolkit.
 #                    This file is the main component of the CImg Library project.
 #                    ( http://cimg.sourceforge.net )
 #
 #  Project manager : David Tschumperle.
 #                    ( http://www.greyc.ensicaen.fr/~dtschump/ )
 #
 #                    The complete list of contributors is available in file 'README.txt'
 #                    distributed within the CImg package.
 #
 #  Licenses        : This file is 'dual-licensed', you have to choose one
 #                    of the two licenses below to apply.
 #
 #                    CeCILL-C
 #                    The CeCILL-C license is close to the GNU LGPL.
 #                    ( http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html )
 #
 #                or  CeCILL v2.0
 #                    The CeCILL license is compatible with the GNU GPL.
 #                    ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
 #
 #  This software is governed either by the CeCILL or the CeCILL-C license
 #  under French law and abiding by the rules of distribution of free software.
 #  You can  use, modify and or redistribute the software under the terms of
 #  the CeCILL or CeCILL-C licenses as circulated by CEA, CNRS and INRIA
 #  at the following URL : "http://www.cecill.info".
 #
 #  As a counterpart to the access to the source code and  rights to copy,
 #  modify and redistribute granted by the license, users are provided only
 #  with a limited warranty  and the software's author,  the holder of the
 #  economic rights,  and the successive licensors  have only  limited
 #  liability.
 #
 #  In this respect, the user's attention is drawn to the risks associated
 #  with loading,  using,  modifying and/or developing or reproducing the
 #  software by the user in light of its specific status of free software,
 #  that may mean  that it is complicated to manipulate,  and  that  also
 #  therefore means  that it is reserved for developers  and  experienced
 #  professionals having in-depth computer knowledge. Users are therefore
 #  encouraged to load and test the software's suitability as regards their
 #  requirements in conditions enabling the security of their systems and/or
 #  data to be ensured and,  more generally, to use and operate it in the
 #  same conditions as regards security.
 #
 #  The fact that you are presently reading this means that you have had
 #  knowledge of the CeCILL and CeCILL-C licenses and that you accept its terms.
 #
*/

// Define version number of the library file.
#ifndef cimg_version
#define cimg_version 149

/*-----------------------------------------------------------
 #
 # Test and auto-set CImg configuration variables
 # and include required headers.
 #
 # If you find that default configuration variables are
 # not adapted to your case, you can override their values
 # before including the header file "CImg.h"
 # (use the #define directive).
 #
 ------------------------------------------------------------*/

// Include required standard C++ headers.
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <cstring>
#include <cmath>
#include <ctime>
#include <exception>

// Operating system configuration.
//
// Define 'cimg_OS' to : '0' for an unknown OS (will try to minize library dependancies).
//                       '1' for a Unix-like OS (Linux, Solaris, BSD, MacOSX, Irix, ...).
//                       '2' for Microsoft Windows.
//                       (autodetection is done by default).
#ifndef cimg_OS
#if defined(unix)        || defined(__unix)      || defined(__unix__) \
 || defined(linux)       || defined(__linux)     || defined(__linux__) \
 || defined(sun)         || defined(__sun) \
 || defined(BSD)         || defined(__OpenBSD__) || defined(__NetBSD__) \
 || defined(__FreeBSD__) || defined __DragonFly__ \
 || defined(sgi)         || defined(__sgi) \
 || defined(__MACOSX__)  || defined(__APPLE__) \
 || defined(__CYGWIN__)
#define cimg_OS 1
#elif defined(_MSC_VER) || defined(WIN32)  || defined(_WIN32) || defined(__WIN32__) \
   || defined(WIN64)    || defined(_WIN64) || defined(__WIN64__)
#define cimg_OS 2
#else
#define cimg_OS 0
#endif
#elif !(cimg_OS==0 || cimg_OS==1 || cimg_OS==2)
#error CImg Library : Configuration variable 'cimg_OS' is badly defined.
#error (valid values are '0 = unknown OS', '1 = Unix-like OS', '2 = Microsoft Windows').
#endif

// Disable silly warnings on Microsoft VC++ compilers.
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4311)
#pragma warning(disable:4312)
#pragma warning(disable:4800)
#pragma warning(disable:4804)
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_DEPRECATE 1
#define _CRT_NONSTDC_NO_DEPRECATE 1
#endif

// Include OS-specific headers for system management.
#if cimg_OS==1
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#elif cimg_OS==2
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#ifndef _WIN32_IE
#define _WIN32_IE 0x0400
#endif
#include <shlobj.h>
#include <io.h>
#define cimg_snprintf _snprintf
#define cimg_vsnprintf _vsnprintf
#endif
#ifndef cimg_snprintf
#include <stdio.h>
#define cimg_snprintf snprintf
#define cimg_vsnprintf vsnprintf
#endif

// Filename separator configuration.
//
// Default separator is '/' for Unix-based OS, and '\' or Windows.
#ifndef cimg_file_separator
#if cimg_OS==2
#define cimg_file_separator '\\'
#else
#define cimg_file_separator '/'
#endif
#endif

// Output messages verbosity configuration.
//
// Define 'cimg_verbosity' to : '0' to hide library messages (quiet mode).
//                              '1' to print library messages on the console.
//                              '2' to display library messages on a dialog window (default behavior).
//                              '3' to do as '1' + add extra warnings (may slow down the code !).
//                              '4' to do as '2' + add extra warnings (may slow down the code !).
//
// Define 'cimg_strict_warnings' to replace warning messages by exception throwns.
//
// Define 'cimg_use_vt100' to allow output of color messages (require VT100-compatible terminal).
#ifndef cimg_verbosity
#define cimg_verbosity 2
#elif !(cimg_verbosity==0 || cimg_verbosity==1 || cimg_verbosity==2 || cimg_verbosity==3 || cimg_verbosity==4)
#error CImg Library : Configuration variable 'cimg_verbosity' is badly defined.
#error (should be { 0=quiet | 1=console | 2=dialog | 3=console+warnings | 4=dialog+warnings }).
#endif

// Display framework configuration.
//
// Define 'cimg_display' to : '0' to disable display capabilities.
//                            '1' to use X-Window framework (X11).
//                            '2' to use Microsoft GDI32 framework.
#ifndef cimg_display
#if cimg_OS==0
#define cimg_display 0
#elif cimg_OS==1
#if defined(__MACOSX__) || defined(__APPLE__)
#define cimg_display 1
#else
#define cimg_display 1
#endif
#elif cimg_OS==2
#define cimg_display 2
#endif
#elif !(cimg_display==0 || cimg_display==1 || cimg_display==2)
#error CImg Library : Configuration variable 'cimg_display' is badly defined.
#error (should be { 0=none | 1=X-Window (X11) | 2=Microsoft GDI32 }).
#endif

// Include display-specific headers.
#if cimg_display==1
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <pthread.h>
#ifdef cimg_use_xshm
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
#endif
#ifdef cimg_use_xrandr
#include <X11/extensions/Xrandr.h>
#endif
#endif
#ifndef cimg_appname
#define cimg_appname "CImg"
#endif

// OpenMP configuration.
// (http://www.openmp.org)
//
// Define 'cimg_use_openmp' to enable OpenMP support.
//
// OpenMP directives can be used in few CImg functions to get
// advantages of multi-core CPUs. Using OpenMP is not mandatory.
#ifdef cimg_use_openmp
#include "omp.h"
#define _cimg_static
#else
#define _cimg_static static
#endif

// OpenCV configuration
// (http://opencv.willowgarage.com/wiki/)
//
// Define 'cimg_use_opencv' to enable OpenCV support.
//
// OpenCV can be used to retrieve images from cameras
// (with function 'CImg<T>::load_camera()'.
// Using OpenCV is not mandatory.
#ifdef cimg_use_opencv
#include <cstddef>
#include "cv.h"
#include "highgui.h"
#endif

// LibPNG configuration.
// (http://www.libpng.org)
//
// Define 'cimg_use_png' to enable LibPNG support.
//
// LibPNG can be used in functions 'CImg<T>::{load,save}_png()'
// to get a builtin support of PNG files. Using LibPNG is not mandatory.
#ifdef cimg_use_png
extern "C" {
#include "png.h"
}
#endif

// LibJPEG configuration.
// (http://en.wikipedia.org/wiki/Libjpeg)
//
// Define 'cimg_use_jpeg' to enable LibJPEG support.
//
// LibJPEG can be used in functions 'CImg<T>::{load,save}_jpeg()'
// to get a builtin support of JPEG files. Using LibJPEG is not mandatory.
#ifdef cimg_use_jpeg
extern "C" {
#include "jpeglib.h"
#include "setjmp.h"
}
#endif

// LibTIFF configuration.
// (http://www.libtiff.org)
//
// Define 'cimg_use_tiff' to enable LibTIFF support.
//
// LibTIFF can be used in functions 'CImg[List]<T>::{load,save}_tiff()'
// to get a builtin support of TIFF files. Using LibTIFF is not mandatory.
#ifdef cimg_use_tiff
extern "C" {
#include "tiffio.h"
}
#endif

// LibMINC2 configuration.
// (http://en.wikibooks.org/wiki/MINC/Reference/MINC2.0_File_Format_Reference)
//
// Define 'cimg_use_minc2' to enable LibMINC2 support.
//
// LibMINC2 can be used in functions 'CImg<T>::{load,save}_minc2()'
// to get a builtin support of MINC2 files. Using LibMINC2 is not mandatory.
#ifdef cimg_use_minc2
extern "C" {
#include "minc2.h"
}
#endif

// FFMPEG Avcodec and Avformat libraries configuration.
// (http://www.ffmpeg.org)
//
// Define 'cimg_use_ffmpeg' to enable FFMPEG lib support.
//
// Avcodec and Avformat libraries can be used in functions
// 'CImg[List]<T>::load_ffmpeg()' to get a builtin
// support of various image sequences files.
// Using FFMPEG libraries is not mandatory.
#ifdef cimg_use_ffmpeg
#if (defined(_STDINT_H) || defined(_STDINT_H_)) && !defined(UINT64_C)
#warning "__STDC_CONSTANT_MACROS has to be defined before including <stdint.h>, this file will probably not compile."
#endif
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS // ...or stdint.h doesn't define UINT64_C, needed for libavutil
#endif
extern "C" {
#include "avformat.h"
#include "avcodec.h"
#include "swscale.h"
}
#endif

// Zlib configuration
// (http://www.zlib.net)
//
// Define 'cimg_use_zlib' to enable Zlib support.
//
// Zlib can be used in functions 'CImg[List]<T>::{load,save}_cimg()'
// to allow compressed data in '.cimg' files. Using Zlib is not mandatory.
#ifdef cimg_use_zlib
extern "C" {
#include "zlib.h"
}
#endif

// Magick++ configuration.
// (http://www.imagemagick.org/Magick++)
//
// Define 'cimg_use_magick' to enable Magick++ support.
//
// Magick++ library can be used in functions 'CImg<T>::{load,save}()'
// to get a builtin support of various image formats (PNG,JPEG,TIFF,...).
// Using Magick++ is not mandatory.
#ifdef cimg_use_magick
#include "Magick++.h"
#endif

// FFTW3 configuration.
// (http://www.fftw.org)
//
// Define 'cimg_use_fftw3' to enable libFFTW3 support.
//
// FFTW3 library can be used in functions 'CImg[List]<T>::FFT()' to
// efficiently compute the Fast Fourier Transform of image data.
#ifdef cimg_use_fftw3
extern "C" {
#include "fftw3.h"
}
#endif

// Board configuration
// (http://libboard.sourceforge.net/)
//
// Define 'cimg_use_board' to enable Board support.
//
// Board library can be used in functions 'CImg<T>::draw_object3d()'
// to draw objects 3d in vector-graphics canvas that can be saved
// as .PS or .SVG files afterwards.
#ifdef cimg_use_board
#ifdef None
#undef None
#define _cimg_redefine_None
#endif
#include "Board.h"
#endif

// OpenEXR configuration
// (http://www.openexr.com/)
//
// Define 'cimg_use_openexr' to enable OpenEXR support.
//
// OpenEXR can be used to read/write .exr file formats.
#ifdef cimg_use_openexr
#include "ImfRgbaFile.h"
#include "ImfInputFile.h"
#include "ImfChannelList.h"
#include "ImfMatrixAttribute.h"
#include "ImfArray.h"
#endif

// Lapack configuration.
// (http://www.netlib.org/lapack)
//
// Define 'cimg_use_lapack' to enable LAPACK support.
//
// Lapack can be used in various CImg functions dealing with
// matrix computation and algorithms (eigenvalues, inverse, ...).
// Using Lapack is not mandatory.
#ifdef cimg_use_lapack
extern "C" {
  extern void sgetrf_(int*, int*, float*, int*, int*, int*);
  extern void sgetri_(int*, float*, int*, int*, float*, int*, int*);
  extern void sgetrs_(char*, int*, int*, float*, int*, int*, float*, int*, int*);
  extern void sgesvd_(char*, char*, int*, int*, float*, int*, float*, float*, int*, float*, int*, float*, int*, int*);
  extern void ssyev_(char*, char*, int*, float*, int*, float*, float*, int*, int*);
  extern void dgetrf_(int*, int*, double*, int*, int*, int*);
  extern void dgetri_(int*, double*, int*, int*, double*, int*, int*);
  extern void dgetrs_(char*, int*, int*, double*, int*, int*, double*, int*, int*);
  extern void dgesvd_(char*, char*, int*, int*, double*, int*, double*, double*, int*, double*, int*, double*, int*, int*);
  extern void dsyev_(char*, char*, int*, double*, int*, double*, double*, int*, int*);
}
#endif

// Check if min/max/PI macros are defined.
//
// CImg does not compile if macros 'min', 'max' or 'PI' are defined,
// because min(), max() and PI labels are defined and used in the cimg:: namespace.
// so it '#undef' these macros if necessary, and restore them to reasonable
// values at the end of the file.
#ifdef min
#undef min
#define _cimg_redefine_min
#endif
#ifdef max
#undef max
#define _cimg_redefine_max
#endif
#ifdef PI
#undef PI
#define _cimg_redefine_PI
#endif

/*------------------------------------------------------------------------------
  #
  # Define user-friendly macros.
  #
  # User macros are prefixed by 'cimg_' and can be used in your own code.
  # They are particularly useful for option parsing, and image loops creation.
  #
  ------------------------------------------------------------------------------*/

// Define the program usage, and retrieve command line arguments.
#define cimg_usage(usage) cimg_library::cimg::option((char*)0,argc,argv,(char*)0,usage,false)
#define cimg_help(str) cimg_library::cimg::option((char*)0,argc,argv,str,(char*)0)
#define cimg_option(name,defaut,usage) cimg_library::cimg::option(name,argc,argv,defaut,usage)
#define cimg_argument(pos) cimg_library::cimg::argument(pos,argc,argv)
#define cimg_argument1(pos,s0) cimg_library::cimg::argument(pos,argc,argv,1,s0)
#define cimg_argument2(pos,s0,s1) cimg_library::cimg::argument(pos,argc,argv,2,s0,s1)
#define cimg_argument3(pos,s0,s1,s2) cimg_library::cimg::argument(pos,argc,argv,3,s0,s1,s2)
#define cimg_argument4(pos,s0,s1,s2,s3) cimg_library::cimg::argument(pos,argc,argv,4,s0,s1,s2,s3)
#define cimg_argument5(pos,s0,s1,s2,s3,s4) cimg_library::cimg::argument(pos,argc,argv,5,s0,s1,s2,s3,s4)
#define cimg_argument6(pos,s0,s1,s2,s3,s4,s5) cimg_library::cimg::argument(pos,argc,argv,6,s0,s1,s2,s3,s4,s5)
#define cimg_argument7(pos,s0,s1,s2,s3,s4,s5,s6) cimg_library::cimg::argument(pos,argc,argv,7,s0,s1,s2,s3,s4,s5,s6)
#define cimg_argument8(pos,s0,s1,s2,s3,s4,s5,s6,s7) cimg_library::cimg::argument(pos,argc,argv,8,s0,s1,s2,s3,s4,s5,s6,s7)
#define cimg_argument9(pos,s0,s1,s2,s3,s4,s5,s6,s7,s8) cimg_library::cimg::argument(pos,argc,argv,9,s0,s1,s2,s3,s4,s5,s6,s7,s8)

// Define and manipulate local neighborhoods.
#define CImg_2x2(I,T) T I[4]; \
                      T& I##cc = I[0]; T& I##nc = I[1]; \
                      T& I##cn = I[2]; T& I##nn = I[3]; \
                      I##cc = I##nc = \
                      I##cn = I##nn = 0

#define CImg_3x3(I,T) T I[9]; \
                      T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; \
                      T& I##pc = I[3]; T& I##cc = I[4]; T& I##nc = I[5]; \
                      T& I##pn = I[6]; T& I##cn = I[7]; T& I##nn = I[8]; \
                      I##pp = I##cp = I##np = \
                      I##pc = I##cc = I##nc = \
                      I##pn = I##cn = I##nn = 0

#define CImg_4x4(I,T) T I[16]; \
                      T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; T& I##ap = I[3]; \
                      T& I##pc = I[4]; T& I##cc = I[5]; T& I##nc = I[6]; T& I##ac = I[7]; \
                      T& I##pn = I[8]; T& I##cn = I[9]; T& I##nn = I[10]; T& I##an = I[11]; \
                      T& I##pa = I[12]; T& I##ca = I[13]; T& I##na = I[14]; T& I##aa = I[15]; \
                      I##pp = I##cp = I##np = I##ap = \
                      I##pc = I##cc = I##nc = I##ac = \
                      I##pn = I##cn = I##nn = I##an = \
                      I##pa = I##ca = I##na = I##aa = 0

#define CImg_5x5(I,T) T I[25]; \
                      T& I##bb = I[0]; T& I##pb = I[1]; T& I##cb = I[2]; T& I##nb = I[3]; T& I##ab = I[4]; \
                      T& I##bp = I[5]; T& I##pp = I[6]; T& I##cp = I[7]; T& I##np = I[8]; T& I##ap = I[9]; \
                      T& I##bc = I[10]; T& I##pc = I[11]; T& I##cc = I[12]; T& I##nc = I[13]; T& I##ac = I[14]; \
                      T& I##bn = I[15]; T& I##pn = I[16]; T& I##cn = I[17]; T& I##nn = I[18]; T& I##an = I[19]; \
                      T& I##ba = I[20]; T& I##pa = I[21]; T& I##ca = I[22]; T& I##na = I[23]; T& I##aa = I[24]; \
                      I##bb = I##pb = I##cb = I##nb = I##ab = \
                      I##bp = I##pp = I##cp = I##np = I##ap = \
                      I##bc = I##pc = I##cc = I##nc = I##ac = \
                      I##bn = I##pn = I##cn = I##nn = I##an = \
                      I##ba = I##pa = I##ca = I##na = I##aa = 0

#define CImg_2x2x2(I,T) T I[8]; \
                      T& I##ccc = I[0]; T& I##ncc = I[1]; \
                      T& I##cnc = I[2]; T& I##nnc = I[3]; \
                      T& I##ccn = I[4]; T& I##ncn = I[5]; \
                      T& I##cnn = I[6]; T& I##nnn = I[7]; \
                      I##ccc = I##ncc = \
                      I##cnc = I##nnc = \
                      I##ccn = I##ncn = \
                      I##cnn = I##nnn = 0

#define CImg_3x3x3(I,T) T I[27]; \
                      T& I##ppp = I[0]; T& I##cpp = I[1]; T& I##npp = I[2]; \
                      T& I##pcp = I[3]; T& I##ccp = I[4]; T& I##ncp = I[5]; \
                      T& I##pnp = I[6]; T& I##cnp = I[7]; T& I##nnp = I[8]; \
                      T& I##ppc = I[9]; T& I##cpc = I[10]; T& I##npc = I[11]; \
                      T& I##pcc = I[12]; T& I##ccc = I[13]; T& I##ncc = I[14]; \
                      T& I##pnc = I[15]; T& I##cnc = I[16]; T& I##nnc = I[17]; \
                      T& I##ppn = I[18]; T& I##cpn = I[19]; T& I##npn = I[20]; \
                      T& I##pcn = I[21]; T& I##ccn = I[22]; T& I##ncn = I[23]; \
                      T& I##pnn = I[24]; T& I##cnn = I[25]; T& I##nnn = I[26]; \
                      I##ppp = I##cpp = I##npp = \
                      I##pcp = I##ccp = I##ncp = \
                      I##pnp = I##cnp = I##nnp = \
                      I##ppc = I##cpc = I##npc = \
                      I##pcc = I##ccc = I##ncc = \
                      I##pnc = I##cnc = I##nnc = \
                      I##ppn = I##cpn = I##npn = \
                      I##pcn = I##ccn = I##ncn = \
                      I##pnn = I##cnn = I##nnn = 0

#define cimg_get2x2(img,x,y,z,c,I,T) \
  I[0] = (T)(img)(x,y,z,c), I[1] = (T)(img)(_n1##x,y,z,c), I[2] = (T)(img)(x,_n1##y,z,c), I[3] = (T)(img)(_n1##x,_n1##y,z,c)

#define cimg_get3x3(img,x,y,z,c,I,T) \
  I[0] = (T)(img)(_p1##x,_p1##y,z,c), I[1] = (T)(img)(x,_p1##y,z,c), I[2] = (T)(img)(_n1##x,_p1##y,z,c), I[3] = (T)(img)(_p1##x,y,z,c), \
  I[4] = (T)(img)(x,y,z,c), I[5] = (T)(img)(_n1##x,y,z,c), I[6] = (T)(img)(_p1##x,_n1##y,z,c), I[7] = (T)(img)(x,_n1##y,z,c), \
  I[8] = (T)(img)(_n1##x,_n1##y,z,c)

#define cimg_get4x4(img,x,y,z,c,I,T) \
  I[0] = (T)(img)(_p1##x,_p1##y,z,c), I[1] = (T)(img)(x,_p1##y,z,c), I[2] = (T)(img)(_n1##x,_p1##y,z,c), I[3] = (T)(img)(_n2##x,_p1##y,z,c), \
  I[4] = (T)(img)(_p1##x,y,z,c), I[5] = (T)(img)(x,y,z,c), I[6] = (T)(img)(_n1##x,y,z,c), I[7] = (T)(img)(_n2##x,y,z,c), \
  I[8] = (T)(img)(_p1##x,_n1##y,z,c), I[9] = (T)(img)(x,_n1##y,z,c), I[10] = (T)(img)(_n1##x,_n1##y,z,c), I[11] = (T)(img)(_n2##x,_n1##y,z,c), \
  I[12] = (T)(img)(_p1##x,_n2##y,z,c), I[13] = (T)(img)(x,_n2##y,z,c), I[14] = (T)(img)(_n1##x,_n2##y,z,c), I[15] = (T)(img)(_n2##x,_n2##y,z,c)

#define cimg_get5x5(img,x,y,z,c,I,T) \
  I[0] = (T)(img)(_p2##x,_p2##y,z,c), I[1] = (T)(img)(_p1##x,_p2##y,z,c), I[2] = (T)(img)(x,_p2##y,z,c), I[3] = (T)(img)(_n1##x,_p2##y,z,c), \
  I[4] = (T)(img)(_n2##x,_p2##y,z,c), I[5] = (T)(img)(_p2##x,_p1##y,z,c), I[6] = (T)(img)(_p1##x,_p1##y,z,c), I[7] = (T)(img)(x,_p1##y,z,c), \
  I[8] = (T)(img)(_n1##x,_p1##y,z,c), I[9] = (T)(img)(_n2##x,_p1##y,z,c), I[10] = (T)(img)(_p2##x,y,z,c), I[11] = (T)(img)(_p1##x,y,z,c), \
  I[12] = (T)(img)(x,y,z,c), I[13] = (T)(img)(_n1##x,y,z,c), I[14] = (T)(img)(_n2##x,y,z,c), I[15] = (T)(img)(_p2##x,_n1##y,z,c), \
  I[16] = (T)(img)(_p1##x,_n1##y,z,c), I[17] = (T)(img)(x,_n1##y,z,c), I[18] = (T)(img)(_n1##x,_n1##y,z,c), I[19] = (T)(img)(_n2##x,_n1##y,z,c), \
  I[20] = (T)(img)(_p2##x,_n2##y,z,c), I[21] = (T)(img)(_p1##x,_n2##y,z,c), I[22] = (T)(img)(x,_n2##y,z,c), I[23] = (T)(img)(_n1##x,_n2##y,z,c), \
  I[24] = (T)(img)(_n2##x,_n2##y,z,c)

#define cimg_get6x6(img,x,y,z,c,I,T) \
 I[0] = (T)(img)(_p2##x,_p2##y,z,c), I[1] = (T)(img)(_p1##x,_p2##y,z,c), I[2] = (T)(img)(x,_p2##y,z,c), I[3] = (T)(img)(_n1##x,_p2##y,z,c), \
 I[4] = (T)(img)(_n2##x,_p2##y,z,c), I[5] = (T)(img)(_n3##x,_p2##y,z,c), I[6] = (T)(img)(_p2##x,_p1##y,z,c), I[7] = (T)(img)(_p1##x,_p1##y,z,c), \
 I[8] = (T)(img)(x,_p1##y,z,c), I[9] = (T)(img)(_n1##x,_p1##y,z,c), I[10] = (T)(img)(_n2##x,_p1##y,z,c), I[11] = (T)(img)(_n3##x,_p1##y,z,c), \
 I[12] = (T)(img)(_p2##x,y,z,c), I[13] = (T)(img)(_p1##x,y,z,c), I[14] = (T)(img)(x,y,z,c), I[15] = (T)(img)(_n1##x,y,z,c), \
 I[16] = (T)(img)(_n2##x,y,z,c), I[17] = (T)(img)(_n3##x,y,z,c), I[18] = (T)(img)(_p2##x,_n1##y,z,c), I[19] = (T)(img)(_p1##x,_n1##y,z,c), \
 I[20] = (T)(img)(x,_n1##y,z,c), I[21] = (T)(img)(_n1##x,_n1##y,z,c), I[22] = (T)(img)(_n2##x,_n1##y,z,c), I[23] = (T)(img)(_n3##x,_n1##y,z,c), \
 I[24] = (T)(img)(_p2##x,_n2##y,z,c), I[25] = (T)(img)(_p1##x,_n2##y,z,c), I[26] = (T)(img)(x,_n2##y,z,c), I[27] = (T)(img)(_n1##x,_n2##y,z,c), \
 I[28] = (T)(img)(_n2##x,_n2##y,z,c), I[29] = (T)(img)(_n3##x,_n2##y,z,c), I[30] = (T)(img)(_p2##x,_n3##y,z,c), I[31] = (T)(img)(_p1##x,_n3##y,z,c), \
 I[32] = (T)(img)(x,_n3##y,z,c), I[33] = (T)(img)(_n1##x,_n3##y,z,c), I[34] = (T)(img)(_n2##x,_n3##y,z,c), I[35] = (T)(img)(_n3##x,_n3##y,z,c)

#define cimg_get7x7(img,x,y,z,c,I,T) \
 I[0] = (T)(img)(_p3##x,_p3##y,z,c), I[1] = (T)(img)(_p2##x,_p3##y,z,c), I[2] = (T)(img)(_p1##x,_p3##y,z,c), I[3] = (T)(img)(x,_p3##y,z,c), \
 I[4] = (T)(img)(_n1##x,_p3##y,z,c), I[5] = (T)(img)(_n2##x,_p3##y,z,c), I[6] = (T)(img)(_n3##x,_p3##y,z,c), I[7] = (T)(img)(_p3##x,_p2##y,z,c), \
 I[8] = (T)(img)(_p2##x,_p2##y,z,c), I[9] = (T)(img)(_p1##x,_p2##y,z,c), I[10] = (T)(img)(x,_p2##y,z,c), I[11] = (T)(img)(_n1##x,_p2##y,z,c), \
 I[12] = (T)(img)(_n2##x,_p2##y,z,c), I[13] = (T)(img)(_n3##x,_p2##y,z,c), I[14] = (T)(img)(_p3##x,_p1##y,z,c), I[15] = (T)(img)(_p2##x,_p1##y,z,c), \
 I[16] = (T)(img)(_p1##x,_p1##y,z,c), I[17] = (T)(img)(x,_p1##y,z,c), I[18] = (T)(img)(_n1##x,_p1##y,z,c), I[19] = (T)(img)(_n2##x,_p1##y,z,c), \
 I[20] = (T)(img)(_n3##x,_p1##y,z,c), I[21] = (T)(img)(_p3##x,y,z,c), I[22] = (T)(img)(_p2##x,y,z,c), I[23] = (T)(img)(_p1##x,y,z,c), \
 I[24] = (T)(img)(x,y,z,c), I[25] = (T)(img)(_n1##x,y,z,c), I[26] = (T)(img)(_n2##x,y,z,c), I[27] = (T)(img)(_n3##x,y,z,c), \
 I[28] = (T)(img)(_p3##x,_n1##y,z,c), I[29] = (T)(img)(_p2##x,_n1##y,z,c), I[30] = (T)(img)(_p1##x,_n1##y,z,c), I[31] = (T)(img)(x,_n1##y,z,c), \
 I[32] = (T)(img)(_n1##x,_n1##y,z,c), I[33] = (T)(img)(_n2##x,_n1##y,z,c), I[34] = (T)(img)(_n3##x,_n1##y,z,c), I[35] = (T)(img)(_p3##x,_n2##y,z,c), \
 I[36] = (T)(img)(_p2##x,_n2##y,z,c), I[37] = (T)(img)(_p1##x,_n2##y,z,c), I[38] = (T)(img)(x,_n2##y,z,c), I[39] = (T)(img)(_n1##x,_n2##y,z,c), \
 I[40] = (T)(img)(_n2##x,_n2##y,z,c), I[41] = (T)(img)(_n3##x,_n2##y,z,c), I[42] = (T)(img)(_p3##x,_n3##y,z,c), I[43] = (T)(img)(_p2##x,_n3##y,z,c), \
 I[44] = (T)(img)(_p1##x,_n3##y,z,c), I[45] = (T)(img)(x,_n3##y,z,c), I[46] = (T)(img)(_n1##x,_n3##y,z,c), I[47] = (T)(img)(_n2##x,_n3##y,z,c), \
 I[48] = (T)(img)(_n3##x,_n3##y,z,c)

#define cimg_get8x8(img,x,y,z,c,I,T) \
 I[0] = (T)(img)(_p3##x,_p3##y,z,c), I[1] = (T)(img)(_p2##x,_p3##y,z,c), I[2] = (T)(img)(_p1##x,_p3##y,z,c), I[3] = (T)(img)(x,_p3##y,z,c), \
 I[4] = (T)(img)(_n1##x,_p3##y,z,c), I[5] = (T)(img)(_n2##x,_p3##y,z,c), I[6] = (T)(img)(_n3##x,_p3##y,z,c), I[7] = (T)(img)(_n4##x,_p3##y,z,c), \
 I[8] = (T)(img)(_p3##x,_p2##y,z,c), I[9] = (T)(img)(_p2##x,_p2##y,z,c), I[10] = (T)(img)(_p1##x,_p2##y,z,c), I[11] = (T)(img)(x,_p2##y,z,c), \
 I[12] = (T)(img)(_n1##x,_p2##y,z,c), I[13] = (T)(img)(_n2##x,_p2##y,z,c), I[14] = (T)(img)(_n3##x,_p2##y,z,c), I[15] = (T)(img)(_n4##x,_p2##y,z,c), \
 I[16] = (T)(img)(_p3##x,_p1##y,z,c), I[17] = (T)(img)(_p2##x,_p1##y,z,c), I[18] = (T)(img)(_p1##x,_p1##y,z,c), I[19] = (T)(img)(x,_p1##y,z,c), \
 I[20] = (T)(img)(_n1##x,_p1##y,z,c), I[21] = (T)(img)(_n2##x,_p1##y,z,c), I[22] = (T)(img)(_n3##x,_p1##y,z,c), I[23] = (T)(img)(_n4##x,_p1##y,z,c), \
 I[24] = (T)(img)(_p3##x,y,z,c), I[25] = (T)(img)(_p2##x,y,z,c), I[26] = (T)(img)(_p1##x,y,z,c), I[27] = (T)(img)(x,y,z,c), \
 I[28] = (T)(img)(_n1##x,y,z,c), I[29] = (T)(img)(_n2##x,y,z,c), I[30] = (T)(img)(_n3##x,y,z,c), I[31] = (T)(img)(_n4##x,y,z,c), \
 I[32] = (T)(img)(_p3##x,_n1##y,z,c), I[33] = (T)(img)(_p2##x,_n1##y,z,c), I[34] = (T)(img)(_p1##x,_n1##y,z,c), I[35] = (T)(img)(x,_n1##y,z,c), \
 I[36] = (T)(img)(_n1##x,_n1##y,z,c), I[37] = (T)(img)(_n2##x,_n1##y,z,c), I[38] = (T)(img)(_n3##x,_n1##y,z,c), I[39] = (T)(img)(_n4##x,_n1##y,z,c), \
 I[40] = (T)(img)(_p3##x,_n2##y,z,c), I[41] = (T)(img)(_p2##x,_n2##y,z,c), I[42] = (T)(img)(_p1##x,_n2##y,z,c), I[43] = (T)(img)(x,_n2##y,z,c), \
 I[44] = (T)(img)(_n1##x,_n2##y,z,c), I[45] = (T)(img)(_n2##x,_n2##y,z,c), I[46] = (T)(img)(_n3##x,_n2##y,z,c), I[47] = (T)(img)(_n4##x,_n2##y,z,c), \
 I[48] = (T)(img)(_p3##x,_n3##y,z,c), I[49] = (T)(img)(_p2##x,_n3##y,z,c), I[50] = (T)(img)(_p1##x,_n3##y,z,c), I[51] = (T)(img)(x,_n3##y,z,c), \
 I[52] = (T)(img)(_n1##x,_n3##y,z,c), I[53] = (T)(img)(_n2##x,_n3##y,z,c), I[54] = (T)(img)(_n3##x,_n3##y,z,c), I[55] = (T)(img)(_n4##x,_n3##y,z,c), \
 I[56] = (T)(img)(_p3##x,_n4##y,z,c), I[57] = (T)(img)(_p2##x,_n4##y,z,c), I[58] = (T)(img)(_p1##x,_n4##y,z,c), I[59] = (T)(img)(x,_n4##y,z,c), \
 I[60] = (T)(img)(_n1##x,_n4##y,z,c), I[61] = (T)(img)(_n2##x,_n4##y,z,c), I[62] = (T)(img)(_n3##x,_n4##y,z,c), I[63] = (T)(img)(_n4##x,_n4##y,z,c);

#define cimg_get9x9(img,x,y,z,c,I,T) \
 I[0] = (T)(img)(_p4##x,_p4##y,z,c), I[1] = (T)(img)(_p3##x,_p4##y,z,c), I[2] = (T)(img)(_p2##x,_p4##y,z,c), I[3] = (T)(img)(_p1##x,_p4##y,z,c), \
 I[4] = (T)(img)(x,_p4##y,z,c), I[5] = (T)(img)(_n1##x,_p4##y,z,c), I[6] = (T)(img)(_n2##x,_p4##y,z,c), I[7] = (T)(img)(_n3##x,_p4##y,z,c), \
 I[8] = (T)(img)(_n4##x,_p4##y,z,c), I[9] = (T)(img)(_p4##x,_p3##y,z,c), I[10] = (T)(img)(_p3##x,_p3##y,z,c), I[11] = (T)(img)(_p2##x,_p3##y,z,c), \
 I[12] = (T)(img)(_p1##x,_p3##y,z,c), I[13] = (T)(img)(x,_p3##y,z,c), I[14] = (T)(img)(_n1##x,_p3##y,z,c), I[15] = (T)(img)(_n2##x,_p3##y,z,c), \
 I[16] = (T)(img)(_n3##x,_p3##y,z,c), I[17] = (T)(img)(_n4##x,_p3##y,z,c), I[18] = (T)(img)(_p4##x,_p2##y,z,c), I[19] = (T)(img)(_p3##x,_p2##y,z,c), \
 I[20] = (T)(img)(_p2##x,_p2##y,z,c), I[21] = (T)(img)(_p1##x,_p2##y,z,c), I[22] = (T)(img)(x,_p2##y,z,c), I[23] = (T)(img)(_n1##x,_p2##y,z,c), \
 I[24] = (T)(img)(_n2##x,_p2##y,z,c), I[25] = (T)(img)(_n3##x,_p2##y,z,c), I[26] = (T)(img)(_n4##x,_p2##y,z,c), I[27] = (T)(img)(_p4##x,_p1##y,z,c), \
 I[28] = (T)(img)(_p3##x,_p1##y,z,c), I[29] = (T)(img)(_p2##x,_p1##y,z,c), I[30] = (T)(img)(_p1##x,_p1##y,z,c), I[31] = (T)(img)(x,_p1##y,z,c), \
 I[32] = (T)(img)(_n1##x,_p1##y,z,c), I[33] = (T)(img)(_n2##x,_p1##y,z,c), I[34] = (T)(img)(_n3##x,_p1##y,z,c), I[35] = (T)(img)(_n4##x,_p1##y,z,c), \
 I[36] = (T)(img)(_p4##x,y,z,c), I[37] = (T)(img)(_p3##x,y,z,c), I[38] = (T)(img)(_p2##x,y,z,c), I[39] = (T)(img)(_p1##x,y,z,c), \
 I[40] = (T)(img)(x,y,z,c), I[41] = (T)(img)(_n1##x,y,z,c), I[42] = (T)(img)(_n2##x,y,z,c), I[43] = (T)(img)(_n3##x,y,z,c), \
 I[44] = (T)(img)(_n4##x,y,z,c), I[45] = (T)(img)(_p4##x,_n1##y,z,c), I[46] = (T)(img)(_p3##x,_n1##y,z,c), I[47] = (T)(img)(_p2##x,_n1##y,z,c), \
 I[48] = (T)(img)(_p1##x,_n1##y,z,c), I[49] = (T)(img)(x,_n1##y,z,c), I[50] = (T)(img)(_n1##x,_n1##y,z,c), I[51] = (T)(img)(_n2##x,_n1##y,z,c), \
 I[52] = (T)(img)(_n3##x,_n1##y,z,c), I[53] = (T)(img)(_n4##x,_n1##y,z,c), I[54] = (T)(img)(_p4##x,_n2##y,z,c), I[55] = (T)(img)(_p3##x,_n2##y,z,c), \
 I[56] = (T)(img)(_p2##x,_n2##y,z,c), I[57] = (T)(img)(_p1##x,_n2##y,z,c), I[58] = (T)(img)(x,_n2##y,z,c), I[59] = (T)(img)(_n1##x,_n2##y,z,c), \
 I[60] = (T)(img)(_n2##x,_n2##y,z,c), I[61] = (T)(img)(_n3##x,_n2##y,z,c), I[62] = (T)(img)(_n4##x,_n2##y,z,c), I[63] = (T)(img)(_p4##x,_n3##y,z,c), \
 I[64] = (T)(img)(_p3##x,_n3##y,z,c), I[65] = (T)(img)(_p2##x,_n3##y,z,c), I[66] = (T)(img)(_p1##x,_n3##y,z,c), I[67] = (T)(img)(x,_n3##y,z,c), \
 I[68] = (T)(img)(_n1##x,_n3##y,z,c), I[69] = (T)(img)(_n2##x,_n3##y,z,c), I[70] = (T)(img)(_n3##x,_n3##y,z,c), I[71] = (T)(img)(_n4##x,_n3##y,z,c), \
 I[72] = (T)(img)(_p4##x,_n4##y,z,c), I[73] = (T)(img)(_p3##x,_n4##y,z,c), I[74] = (T)(img)(_p2##x,_n4##y,z,c), I[75] = (T)(img)(_p1##x,_n4##y,z,c), \
 I[76] = (T)(img)(x,_n4##y,z,c), I[77] = (T)(img)(_n1##x,_n4##y,z,c), I[78] = (T)(img)(_n2##x,_n4##y,z,c), I[79] = (T)(img)(_n3##x,_n4##y,z,c), \
 I[80] = (T)(img)(_n4##x,_n4##y,z,c)

#define cimg_get2x2x2(img,x,y,z,c,I,T) \
  I[0] = (T)(img)(x,y,z,c), I[1] = (T)(img)(_n1##x,y,z,c), I[2] = (T)(img)(x,_n1##y,z,c), I[3] = (T)(img)(_n1##x,_n1##y,z,c), \
  I[4] = (T)(img)(x,y,_n1##z,c), I[5] = (T)(img)(_n1##x,y,_n1##z,c), I[6] = (T)(img)(x,_n1##y,_n1##z,c), I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c)

#define cimg_get3x3x3(img,x,y,z,c,I,T) \
  I[0] = (T)(img)(_p1##x,_p1##y,_p1##z,c), I[1] = (T)(img)(x,_p1##y,_p1##z,c), I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c), \
  I[3] = (T)(img)(_p1##x,y,_p1##z,c), I[4] = (T)(img)(x,y,_p1##z,c), I[5] = (T)(img)(_n1##x,y,_p1##z,c), \
  I[6] = (T)(img)(_p1##x,_n1##y,_p1##z,c), I[7] = (T)(img)(x,_n1##y,_p1##z,c), I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c), \
  I[9] = (T)(img)(_p1##x,_p1##y,z,c), I[10] = (T)(img)(x,_p1##y,z,c), I[11] = (T)(img)(_n1##x,_p1##y,z,c), \
  I[12] = (T)(img)(_p1##x,y,z,c), I[13] = (T)(img)(x,y,z,c), I[14] = (T)(img)(_n1##x,y,z,c), \
  I[15] = (T)(img)(_p1##x,_n1##y,z,c), I[16] = (T)(img)(x,_n1##y,z,c), I[17] = (T)(img)(_n1##x,_n1##y,z,c), \
  I[18] = (T)(img)(_p1##x,_p1##y,_n1##z,c), I[19] = (T)(img)(x,_p1##y,_n1##z,c), I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c), \
  I[21] = (T)(img)(_p1##x,y,_n1##z,c), I[22] = (T)(img)(x,y,_n1##z,c), I[23] = (T)(img)(_n1##x,y,_n1##z,c), \
  I[24] = (T)(img)(_p1##x,_n1##y,_n1##z,c), I[25] = (T)(img)(x,_n1##y,_n1##z,c), I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c)

// Define various image loops.
//
// These macros generally avoid the use of iterators, but you are not forced to used them !
#define cimg_for(img,ptrs,T_ptrs) for (T_ptrs *ptrs = (img)._data + (img).size(); (ptrs--)>(img)._data; )
#define cimg_foroff(img,off) for (unsigned int off = 0, _max##off = (unsigned int)(img).size(); off<_max##off; ++off)

#define cimg_for1(bound,i) for (int i = 0; i<(int)(bound); ++i)
#define cimg_forX(img,x) cimg_for1((img)._width,x)
#define cimg_forY(img,y) cimg_for1((img)._height,y)
#define cimg_forZ(img,z) cimg_for1((img)._depth,z)
#define cimg_forC(img,c) cimg_for1((img)._spectrum,c)
#define cimg_forXY(img,x,y) cimg_forY(img,y) cimg_forX(img,x)
#define cimg_forXZ(img,x,z) cimg_forZ(img,z) cimg_forX(img,x)
#define cimg_forYZ(img,y,z) cimg_forZ(img,z) cimg_forY(img,y)
#define cimg_forXC(img,x,c) cimg_forC(img,c) cimg_forX(img,x)
#define cimg_forYC(img,y,c) cimg_forC(img,c) cimg_forY(img,y)
#define cimg_forZC(img,z,c) cimg_forC(img,c) cimg_forZ(img,z)
#define cimg_forXYZ(img,x,y,z) cimg_forZ(img,z) cimg_forXY(img,x,y)
#define cimg_forXYC(img,x,y,c) cimg_forC(img,c) cimg_forXY(img,x,y)
#define cimg_forXZC(img,x,z,c) cimg_forC(img,c) cimg_forXZ(img,x,z)
#define cimg_forYZC(img,y,z,c) cimg_forC(img,c) cimg_forYZ(img,y,z)
#define cimg_forXYZC(img,x,y,z,c) cimg_forC(img,c) cimg_forXYZ(img,x,y,z)

#define cimg_for_in1(bound,i0,i1,i) \
 for (int i = (int)(i0)<0?0:(int)(i0), _max##i = (int)(i1)<(int)(bound)?(int)(i1):(int)(bound)-1; i<=_max##i; ++i)
#define cimg_for_inX(img,x0,x1,x) cimg_for_in1((img)._width,x0,x1,x)
#define cimg_for_inY(img,y0,y1,y) cimg_for_in1((img)._height,y0,y1,y)
#define cimg_for_inZ(img,z0,z1,z) cimg_for_in1((img)._depth,z0,z1,z)
#define cimg_for_inC(img,c0,c1,c) cimg_for_in1((img)._spectrum,c0,c1,c)
#define cimg_for_inXY(img,x0,y0,x1,y1,x,y) cimg_for_inY(img,y0,y1,y) cimg_for_inX(img,x0,x1,x)
#define cimg_for_inXZ(img,x0,z0,x1,z1,x,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inX(img,x0,x1,x)
#define cimg_for_inXC(img,x0,c0,x1,c1,x,c) cimg_for_inC(img,c0,c1,c) cimg_for_inX(img,x0,x1,x)
#define cimg_for_inYZ(img,y0,z0,y1,z1,y,z) cimg_for_inZ(img,x0,z1,z) cimg_for_inY(img,y0,y1,y)
#define cimg_for_inYC(img,y0,c0,y1,c1,y,c) cimg_for_inC(img,c0,c1,c) cimg_for_inY(img,y0,y1,y)
#define cimg_for_inZC(img,z0,c0,z1,c1,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inZ(img,z0,z1,z)
#define cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inXY(img,x0,y0,x1,y1,x,y)
#define cimg_for_inXYC(img,x0,y0,c0,x1,y1,c1,x,y,c) cimg_for_inC(img,c0,c1,c) cimg_for_inXY(img,x0,y0,x1,y1,x,y)
#define cimg_for_inXZC(img,x0,z0,c0,x1,z1,c1,x,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inXZ(img,x0,z0,x1,z1,x,z)
#define cimg_for_inYZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inYZ(img,y0,z0,y1,z1,y,z)
#define cimg_for_inXYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
#define cimg_for_insideX(img,x,n) cimg_for_inX(img,n,(img)._width-1-(n),x)
#define cimg_for_insideY(img,y,n) cimg_for_inY(img,n,(img)._height-1-(n),y)
#define cimg_for_insideZ(img,z,n) cimg_for_inZ(img,n,(img)._depth-1-(n),z)
#define cimg_for_insideC(img,c,n) cimg_for_inC(img,n,(img)._spectrum-1-(n),c)
#define cimg_for_insideXY(img,x,y,n) cimg_for_inXY(img,n,n,(img)._width-1-(n),(img)._height-1-(n),x,y)
#define cimg_for_insideXYZ(img,x,y,z,n) cimg_for_inXYZ(img,n,n,n,(img)._width-1-(n),(img)._height-1-(n),(img)._depth-1-(n),x,y,z)
#define cimg_for_insideXYZC(img,x,y,z,c,n) cimg_for_inXYZ(img,n,n,n,(img)._width-1-(n),(img)._height-1-(n),(img)._depth-1-(n),x,y,z)

#define cimg_for_out1(boundi,i0,i1,i) \
 for (int i = (int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); ++i, i = i==(int)(i0)?(int)(i1)+1:i)
#define cimg_for_out2(boundi,boundj,i0,j0,i1,j1,i,j) \
 for (int j = 0; j<(int)(boundj); ++j) \
 for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
  ++i, i = _n1j?i:(i==(int)(i0)?(int)(i1)+1:i))
#define cimg_for_out3(boundi,boundj,boundk,i0,j0,k0,i1,j1,k1,i,j,k) \
 for (int k = 0; k<(int)(boundk); ++k) \
 for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
 for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
  ++i, i = _n1j || _n1k?i:(i==(int)(i0)?(int)(i1)+1:i))
#define cimg_for_out4(boundi,boundj,boundk,boundl,i0,j0,k0,l0,i1,j1,k1,l1,i,j,k,l) \
 for (int l = 0; l<(int)(boundl); ++l) \
 for (int _n1l = (int)(l<(int)(l0) || l>(int)(l1)), k = 0; k<(int)(boundk); ++k) \
 for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
 for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k || _n1l?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
  ++i, i = _n1j || _n1k || _n1l?i:(i==(int)(i0)?(int)(i1)+1:i))
#define cimg_for_outX(img,x0,x1,x) cimg_for_out1((img)._width,x0,x1,x)
#define cimg_for_outY(img,y0,y1,y) cimg_for_out1((img)._height,y0,y1,y)
#define cimg_for_outZ(img,z0,z1,z) cimg_for_out1((img)._depth,z0,z1,z)
#define cimg_for_outC(img,c0,c1,c) cimg_for_out1((img)._spectrum,c0,c1,c)
#define cimg_for_outXY(img,x0,y0,x1,y1,x,y) cimg_for_out2((img)._width,(img)._height,x0,y0,x1,y1,x,y)
#define cimg_for_outXZ(img,x0,z0,x1,z1,x,z) cimg_for_out2((img)._width,(img)._depth,x0,z0,x1,z1,x,z)
#define cimg_for_outXC(img,x0,c0,x1,c1,x,c) cimg_for_out2((img)._width,(img)._spectrum,x0,c0,x1,c1,x,c)
#define cimg_for_outYZ(img,y0,z0,y1,z1,y,z) cimg_for_out2((img)._height,(img)._depth,y0,z0,y1,z1,y,z)
#define cimg_for_outYC(img,y0,c0,y1,c1,y,c) cimg_for_out2((img)._height,(img)._spectrum,y0,c0,y1,c1,y,c)
#define cimg_for_outZC(img,z0,c0,z1,c1,z,c) cimg_for_out2((img)._depth,(img)._spectrum,z0,c0,z1,c1,z,c)
#define cimg_for_outXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_out3((img)._width,(img)._height,(img)._depth,x0,y0,z0,x1,y1,z1,x,y,z)
#define cimg_for_outXYC(img,x0,y0,c0,x1,y1,c1,x,y,c) cimg_for_out3((img)._width,(img)._height,(img)._spectrum,x0,y0,c0,x1,y1,c1,x,y,c)
#define cimg_for_outXZC(img,x0,z0,c0,x1,z1,c1,x,z,c) cimg_for_out3((img)._width,(img)._depth,(img)._spectrum,x0,z0,c0,x1,z1,c1,x,z,c)
#define cimg_for_outYZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_out3((img)._height,(img)._depth,(img)._spectrum,y0,z0,c0,y1,z1,c1,y,z,c)
#define cimg_for_outXYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \
 cimg_for_out4((img)._width,(img)._height,(img)._depth,(img)._spectrum,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c)
#define cimg_for_borderX(img,x,n) cimg_for_outX(img,n,(img)._width-1-(n),x)
#define cimg_for_borderY(img,y,n) cimg_for_outY(img,n,(img)._height-1-(n),y)
#define cimg_for_borderZ(img,z,n) cimg_for_outZ(img,n,(img)._depth-1-(n),z)
#define cimg_for_borderC(img,c,n) cimg_for_outC(img,n,(img)._spectrum-1-(n),c)
#define cimg_for_borderXY(img,x,y,n) cimg_for_outXY(img,n,n,(img)._width-1-(n),(img)._height-1-(n),x,y)
#define cimg_for_borderXYZ(img,x,y,z,n) cimg_for_outXYZ(img,n,n,n,(img)._width-1-(n),(img)._height-1-(n),(img)._depth-1-(n),x,y,z)
#define cimg_for_borderXYZC(img,x,y,z,c,n) \
 cimg_for_outXYZC(img,n,n,n,n,(img)._width-1-(n),(img)._height-1-(n),(img)._depth-1-(n),(img)._spectrum-1-(n),x,y,z,c)

#define cimg_for_spiralXY(img,x,y) \
 for (int x = 0, y = 0, _n1##x = 1, _n1##y = (img).width()*(img).height(); _n1##y; \
      --_n1##y, _n1##x+=(_n1##x>>2)-((!(_n1##x&3)?--y:((_n1##x&3)==1?(img)._width-1-++x:((_n1##x&3)==2?(img)._height-1-++y:--x))))?0:1)

#define cimg_for_lineXY(x,y,x0,y0,x1,y1) \
 for (int x = (int)(x0), y = (int)(y0), _sx = 1, _sy = 1, _steep = 0, \
      _dx=(x1)>(x0)?(int)(x1)-(int)(x0):(_sx=-1,(int)(x0)-(int)(x1)), \
      _dy=(y1)>(y0)?(int)(y1)-(int)(y0):(_sy=-1,(int)(y0)-(int)(y1)), \
      _counter = _dx, \
      _err = _dx>_dy?(_dy>>1):((_steep=1),(_counter=_dy),(_dx>>1)); \
      _counter>=0; \
      --_counter, x+=_steep? \
      (y+=_sy,(_err-=_dx)<0?_err+=_dy,_sx:0): \
      (y+=(_err-=_dy)<0?_err+=_dx,_sy:0,_sx))

#define cimg_for2(bound,i) \
 for (int i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1; \
      _n1##i<(int)(bound) || i==--_n1##i; \
      ++i, ++_n1##i)
#define cimg_for2X(img,x) cimg_for2((img)._width,x)
#define cimg_for2Y(img,y) cimg_for2((img)._height,y)
#define cimg_for2Z(img,z) cimg_for2((img)._depth,z)
#define cimg_for2C(img,c) cimg_for2((img)._spectrum,c)
#define cimg_for2XY(img,x,y) cimg_for2Y(img,y) cimg_for2X(img,x)
#define cimg_for2XZ(img,x,z) cimg_for2Z(img,z) cimg_for2X(img,x)
#define cimg_for2XC(img,x,c) cimg_for2C(img,c) cimg_for2X(img,x)
#define cimg_for2YZ(img,y,z) cimg_for2Z(img,z) cimg_for2Y(img,y)
#define cimg_for2YC(img,y,c) cimg_for2C(img,c) cimg_for2Y(img,y)
#define cimg_for2ZC(img,z,c) cimg_for2C(img,c) cimg_for2Z(img,z)
#define cimg_for2XYZ(img,x,y,z) cimg_for2Z(img,z) cimg_for2XY(img,x,y)
#define cimg_for2XZC(img,x,z,c) cimg_for2C(img,c) cimg_for2XZ(img,x,z)
#define cimg_for2YZC(img,y,z,c) cimg_for2C(img,c) cimg_for2YZ(img,y,z)
#define cimg_for2XYZC(img,x,y,z,c) cimg_for2C(img,c) cimg_for2XYZ(img,x,y,z)

#define cimg_for_in2(bound,i0,i1,i) \
 for (int i = (int)(i0)<0?0:(int)(i0), \
      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
      i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
      ++i, ++_n1##i)
#define cimg_for_in2X(img,x0,x1,x) cimg_for_in2((img)._width,x0,x1,x)
#define cimg_for_in2Y(img,y0,y1,y) cimg_for_in2((img)._height,y0,y1,y)
#define cimg_for_in2Z(img,z0,z1,z) cimg_for_in2((img)._depth,z0,z1,z)
#define cimg_for_in2C(img,c0,c1,c) cimg_for_in2((img)._spectrum,c0,c1,c)
#define cimg_for_in2XY(img,x0,y0,x1,y1,x,y) cimg_for_in2Y(img,y0,y1,y) cimg_for_in2X(img,x0,x1,x)
#define cimg_for_in2XZ(img,x0,z0,x1,z1,x,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2X(img,x0,x1,x)
#define cimg_for_in2XC(img,x0,c0,x1,c1,x,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2X(img,x0,x1,x)
#define cimg_for_in2YZ(img,y0,z0,y1,z1,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2Y(img,y0,y1,y)
#define cimg_for_in2YC(img,y0,c0,y1,c1,y,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2Y(img,y0,y1,y)
#define cimg_for_in2ZC(img,z0,c0,z1,c1,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2Z(img,z0,z1,z)
#define cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2XY(img,x0,y0,x1,y1,x,y)
#define cimg_for_in2XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2XZ(img,x0,y0,x1,y1,x,z)
#define cimg_for_in2YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2YZ(img,y0,z0,y1,z1,y,z)
#define cimg_for_in2XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)

#define cimg_for3(bound,i) \
 for (int i = 0, _p1##i = 0, \
      _n1##i = 1>=(bound)?(int)(bound)-1:1; \
      _n1##i<(int)(bound) || i==--_n1##i; \
      _p1##i = i++, ++_n1##i)
#define cimg_for3X(img,x) cimg_for3((img)._width,x)
#define cimg_for3Y(img,y) cimg_for3((img)._height,y)
#define cimg_for3Z(img,z) cimg_for3((img)._depth,z)
#define cimg_for3C(img,c) cimg_for3((img)._spectrum,c)
#define cimg_for3XY(img,x,y) cimg_for3Y(img,y) cimg_for3X(img,x)
#define cimg_for3XZ(img,x,z) cimg_for3Z(img,z) cimg_for3X(img,x)
#define cimg_for3XC(img,x,c) cimg_for3C(img,c) cimg_for3X(img,x)
#define cimg_for3YZ(img,y,z) cimg_for3Z(img,z) cimg_for3Y(img,y)
#define cimg_for3YC(img,y,c) cimg_for3C(img,c) cimg_for3Y(img,y)
#define cimg_for3ZC(img,z,c) cimg_for3C(img,c) cimg_for3Z(img,z)
#define cimg_for3XYZ(img,x,y,z) cimg_for3Z(img,z) cimg_for3XY(img,x,y)
#define cimg_for3XZC(img,x,z,c) cimg_for3C(img,c) cimg_for3XZ(img,x,z)
#define cimg_for3YZC(img,y,z,c) cimg_for3C(img,c) cimg_for3YZ(img,y,z)
#define cimg_for3XYZC(img,x,y,z,c) cimg_for3C(img,c) cimg_for3XYZ(img,x,y,z)

#define cimg_for_in3(bound,i0,i1,i) \
 for (int i = (int)(i0)<0?0:(int)(i0), \
      _p1##i = i-1<0?0:i-1, \
      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
      i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
      _p1##i = i++, ++_n1##i)
#define cimg_for_in3X(img,x0,x1,x) cimg_for_in3((img)._width,x0,x1,x)
#define cimg_for_in3Y(img,y0,y1,y) cimg_for_in3((img)._height,y0,y1,y)
#define cimg_for_in3Z(img,z0,z1,z) cimg_for_in3((img)._depth,z0,z1,z)
#define cimg_for_in3C(img,c0,c1,c) cimg_for_in3((img)._spectrum,c0,c1,c)
#define cimg_for_in3XY(img,x0,y0,x1,y1,x,y) cimg_for_in3Y(img,y0,y1,y) cimg_for_in3X(img,x0,x1,x)
#define cimg_for_in3XZ(img,x0,z0,x1,z1,x,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3X(img,x0,x1,x)
#define cimg_for_in3XC(img,x0,c0,x1,c1,x,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3X(img,x0,x1,x)
#define cimg_for_in3YZ(img,y0,z0,y1,z1,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3Y(img,y0,y1,y)
#define cimg_for_in3YC(img,y0,c0,y1,c1,y,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3Y(img,y0,y1,y)
#define cimg_for_in3ZC(img,z0,c0,z1,c1,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3Z(img,z0,z1,z)
#define cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3XY(img,x0,y0,x1,y1,x,y)
#define cimg_for_in3XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3XZ(img,x0,y0,x1,y1,x,z)
#define cimg_for_in3YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3YZ(img,y0,z0,y1,z1,y,z)
#define cimg_for_in3XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)

#define cimg_for4(bound,i) \
 for (int i = 0, _p1##i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1, \
      _n2##i = 2>=(bound)?(int)(bound)-1:2; \
      _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
      _p1##i = i++, ++_n1##i, ++_n2##i)
#define cimg_for4X(img,x) cimg_for4((img)._width,x)
#define cimg_for4Y(img,y) cimg_for4((img)._height,y)
#define cimg_for4Z(img,z) cimg_for4((img)._depth,z)
#define cimg_for4C(img,c) cimg_for4((img)._spectrum,c)
#define cimg_for4XY(img,x,y) cimg_for4Y(img,y) cimg_for4X(img,x)
#define cimg_for4XZ(img,x,z) cimg_for4Z(img,z) cimg_for4X(img,x)
#define cimg_for4XC(img,x,c) cimg_for4C(img,c) cimg_for4X(img,x)
#define cimg_for4YZ(img,y,z) cimg_for4Z(img,z) cimg_for4Y(img,y)
#define cimg_for4YC(img,y,c) cimg_for4C(img,c) cimg_for4Y(img,y)
#define cimg_for4ZC(img,z,c) cimg_for4C(img,c) cimg_for4Z(img,z)
#define cimg_for4XYZ(img,x,y,z) cimg_for4Z(img,z) cimg_for4XY(img,x,y)
#define cimg_for4XZC(img,x,z,c) cimg_for4C(img,c) cimg_for4XZ(img,x,z)
#define cimg_for4YZC(img,y,z,c) cimg_for4C(img,c) cimg_for4YZ(img,y,z)
#define cimg_for4XYZC(img,x,y,z,c) cimg_for4C(img,c) cimg_for4XYZ(img,x,y,z)

#define cimg_for_in4(bound,i0,i1,i) \
 for (int i = (int)(i0)<0?0:(int)(i0), \
      _p1##i = i-1<0?0:i-1, \
      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
      _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
      i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
      _p1##i = i++, ++_n1##i, ++_n2##i)
#define cimg_for_in4X(img,x0,x1,x) cimg_for_in4((img)._width,x0,x1,x)
#define cimg_for_in4Y(img,y0,y1,y) cimg_for_in4((img)._height,y0,y1,y)
#define cimg_for_in4Z(img,z0,z1,z) cimg_for_in4((img)._depth,z0,z1,z)
#define cimg_for_in4C(img,c0,c1,c) cimg_for_in4((img)._spectrum,c0,c1,c)
#define cimg_for_in4XY(img,x0,y0,x1,y1,x,y) cimg_for_in4Y(img,y0,y1,y) cimg_for_in4X(img,x0,x1,x)
#define cimg_for_in4XZ(img,x0,z0,x1,z1,x,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4X(img,x0,x1,x)
#define cimg_for_in4XC(img,x0,c0,x1,c1,x,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4X(img,x0,x1,x)
#define cimg_for_in4YZ(img,y0,z0,y1,z1,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4Y(img,y0,y1,y)
#define cimg_for_in4YC(img,y0,c0,y1,c1,y,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4Y(img,y0,y1,y)
#define cimg_for_in4ZC(img,z0,c0,z1,c1,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4Z(img,z0,z1,z)
#define cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4XY(img,x0,y0,x1,y1,x,y)
#define cimg_for_in4XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4XZ(img,x0,y0,x1,y1,x,z)
#define cimg_for_in4YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4YZ(img,y0,z0,y1,z1,y,z)
#define cimg_for_in4XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)

#define cimg_for5(bound,i) \
 for (int i = 0, _p2##i = 0, _p1##i = 0, \
      _n1##i = 1>=(bound)?(int)(bound)-1:1, \
      _n2##i = 2>=(bound)?(int)(bound)-1:2; \
      _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
#define cimg_for5X(img,x) cimg_for5((img)._width,x)
#define cimg_for5Y(img,y) cimg_for5((img)._height,y)
#define cimg_for5Z(img,z) cimg_for5((img)._depth,z)
#define cimg_for5C(img,c) cimg_for5((img)._spectrum,c)
#define cimg_for5XY(img,x,y) cimg_for5Y(img,y) cimg_for5X(img,x)
#define cimg_for5XZ(img,x,z) cimg_for5Z(img,z) cimg_for5X(img,x)
#define cimg_for5XC(img,x,c) cimg_for5C(img,c) cimg_for5X(img,x)
#define cimg_for5YZ(img,y,z) cimg_for5Z(img,z) cimg_for5Y(img,y)
#define cimg_for5YC(img,y,c) cimg_for5C(img,c) cimg_for5Y(img,y)
#define cimg_for5ZC(img,z,c) cimg_for5C(img,c) cimg_for5Z(img,z)
#define cimg_for5XYZ(img,x,y,z) cimg_for5Z(img,z) cimg_for5XY(img,x,y)
#define cimg_for5XZC(img,x,z,c) cimg_for5C(img,c) cimg_for5XZ(img,x,z)
#define cimg_for5YZC(img,y,z,c) cimg_for5C(img,c) cimg_for5YZ(img,y,z)
#define cimg_for5XYZC(img,x,y,z,c) cimg_for5C(img,c) cimg_for5XYZ(img,x,y,z)

#define cimg_for_in5(bound,i0,i1,i) \
 for (int i = (int)(i0)<0?0:(int)(i0), \
      _p2##i = i-2<0?0:i-2, \
      _p1##i = i-1<0?0:i-1, \
      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
      _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
      i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
#define cimg_for_in5X(img,x0,x1,x) cimg_for_in5((img)._width,x0,x1,x)
#define cimg_for_in5Y(img,y0,y1,y) cimg_for_in5((img)._height,y0,y1,y)
#define cimg_for_in5Z(img,z0,z1,z) cimg_for_in5((img)._depth,z0,z1,z)
#define cimg_for_in5C(img,c0,c1,c) cimg_for_in5((img)._spectrum,c0,c1,c)
#define cimg_for_in5XY(img,x0,y0,x1,y1,x,y) cimg_for_in5Y(img,y0,y1,y) cimg_for_in5X(img,x0,x1,x)
#define cimg_for_in5XZ(img,x0,z0,x1,z1,x,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5X(img,x0,x1,x)
#define cimg_for_in5XC(img,x0,c0,x1,c1,x,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5X(img,x0,x1,x)
#define cimg_for_in5YZ(img,y0,z0,y1,z1,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5Y(img,y0,y1,y)
#define cimg_for_in5YC(img,y0,c0,y1,c1,y,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5Y(img,y0,y1,y)
#define cimg_for_in5ZC(img,z0,c0,z1,c1,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5Z(img,z0,z1,z)
#define cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5XY(img,x0,y0,x1,y1,x,y)
#define cimg_for_in5XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5XZ(img,x0,y0,x1,y1,x,z)
#define cimg_for_in5YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5YZ(img,y0,z0,y1,z1,y,z)
#define cimg_for_in5XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)

#define cimg_for6(bound,i) \
 for (int i = 0, _p2##i = 0, _p1##i = 0, \
      _n1##i = 1>=(bound)?(int)(bound)-1:1, \
      _n2##i = 2>=(bound)?(int)(bound)-1:2, \
      _n3##i = 3>=(bound)?(int)(bound)-1:3; \
      _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
#define cimg_for6X(img,x) cimg_for6((img)._width,x)
#define cimg_for6Y(img,y) cimg_for6((img)._height,y)
#define cimg_for6Z(img,z) cimg_for6((img)._depth,z)
#define cimg_for6C(img,c) cimg_for6((img)._spectrum,c)
#define cimg_for6XY(img,x,y) cimg_for6Y(img,y) cimg_for6X(img,x)
#define cimg_for6XZ(img,x,z) cimg_for6Z(img,z) cimg_for6X(img,x)
#define cimg_for6XC(img,x,c) cimg_for6C(img,c) cimg_for6X(img,x)
#define cimg_for6YZ(img,y,z) cimg_for6Z(img,z) cimg_for6Y(img,y)
#define cimg_for6YC(img,y,c) cimg_for6C(img,c) cimg_for6Y(img,y)
#define cimg_for6ZC(img,z,c) cimg_for6C(img,c) cimg_for6Z(img,z)
#define cimg_for6XYZ(img,x,y,z) cimg_for6Z(img,z) cimg_for6XY(img,x,y)
#define cimg_for6XZC(img,x,z,c) cimg_for6C(img,c) cimg_for6XZ(img,x,z)
#define cimg_for6YZC(img,y,z,c) cimg_for6C(img,c) cimg_for6YZ(img,y,z)
#define cimg_for6XYZC(img,x,y,z,c) cimg_for6C(img,c) cimg_for6XYZ(img,x,y,z)

#define cimg_for_in6(bound,i0,i1,i) \
 for (int i = (int)(i0)<0?0:(int)(i0), \
      _p2##i = i-2<0?0:i-2, \
      _p1##i = i-1<0?0:i-1, \
      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
      _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
      _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
      i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
#define cimg_for_in6X(img,x0,x1,x) cimg_for_in6((img)._width,x0,x1,x)
#define cimg_for_in6Y(img,y0,y1,y) cimg_for_in6((img)._height,y0,y1,y)
#define cimg_for_in6Z(img,z0,z1,z) cimg_for_in6((img)._depth,z0,z1,z)
#define cimg_for_in6C(img,c0,c1,c) cimg_for_in6((img)._spectrum,c0,c1,c)
#define cimg_for_in6XY(img,x0,y0,x1,y1,x,y) cimg_for_in6Y(img,y0,y1,y) cimg_for_in6X(img,x0,x1,x)
#define cimg_for_in6XZ(img,x0,z0,x1,z1,x,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6X(img,x0,x1,x)
#define cimg_for_in6XC(img,x0,c0,x1,c1,x,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6X(img,x0,x1,x)
#define cimg_for_in6YZ(img,y0,z0,y1,z1,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6Y(img,y0,y1,y)
#define cimg_for_in6YC(img,y0,c0,y1,c1,y,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6Y(img,y0,y1,y)
#define cimg_for_in6ZC(img,z0,c0,z1,c1,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6Z(img,z0,z1,z)
#define cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6XY(img,x0,y0,x1,y1,x,y)
#define cimg_for_in6XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6XZ(img,x0,y0,x1,y1,x,z)
#define cimg_for_in6YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6YZ(img,y0,z0,y1,z1,y,z)
#define cimg_for_in6XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)

#define cimg_for7(bound,i) \
 for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
      _n1##i = 1>=(bound)?(int)(bound)-1:1, \
      _n2##i = 2>=(bound)?(int)(bound)-1:2, \
      _n3##i = 3>=(bound)?(int)(bound)-1:3; \
      _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
#define cimg_for7X(img,x) cimg_for7((img)._width,x)
#define cimg_for7Y(img,y) cimg_for7((img)._height,y)
#define cimg_for7Z(img,z) cimg_for7((img)._depth,z)
#define cimg_for7C(img,c) cimg_for7((img)._spectrum,c)
#define cimg_for7XY(img,x,y) cimg_for7Y(img,y) cimg_for7X(img,x)
#define cimg_for7XZ(img,x,z) cimg_for7Z(img,z) cimg_for7X(img,x)
#define cimg_for7XC(img,x,c) cimg_for7C(img,c) cimg_for7X(img,x)
#define cimg_for7YZ(img,y,z) cimg_for7Z(img,z) cimg_for7Y(img,y)
#define cimg_for7YC(img,y,c) cimg_for7C(img,c) cimg_for7Y(img,y)
#define cimg_for7ZC(img,z,c) cimg_for7C(img,c) cimg_for7Z(img,z)
#define cimg_for7XYZ(img,x,y,z) cimg_for7Z(img,z) cimg_for7XY(img,x,y)
#define cimg_for7XZC(img,x,z,c) cimg_for7C(img,c) cimg_for7XZ(img,x,z)
#define cimg_for7YZC(img,y,z,c) cimg_for7C(img,c) cimg_for7YZ(img,y,z)
#define cimg_for7XYZC(img,x,y,z,c) cimg_for7C(img,c) cimg_for7XYZ(img,x,y,z)

#define cimg_for_in7(bound,i0,i1,i) \
 for (int i = (int)(i0)<0?0:(int)(i0), \
      _p3##i = i-3<0?0:i-3, \
      _p2##i = i-2<0?0:i-2, \
      _p1##i = i-1<0?0:i-1, \
      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
      _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
      _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
      i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
#define cimg_for_in7X(img,x0,x1,x) cimg_for_in7((img)._width,x0,x1,x)
#define cimg_for_in7Y(img,y0,y1,y) cimg_for_in7((img)._height,y0,y1,y)
#define cimg_for_in7Z(img,z0,z1,z) cimg_for_in7((img)._depth,z0,z1,z)
#define cimg_for_in7C(img,c0,c1,c) cimg_for_in7((img)._spectrum,c0,c1,c)
#define cimg_for_in7XY(img,x0,y0,x1,y1,x,y) cimg_for_in7Y(img,y0,y1,y) cimg_for_in7X(img,x0,x1,x)
#define cimg_for_in7XZ(img,x0,z0,x1,z1,x,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7X(img,x0,x1,x)
#define cimg_for_in7XC(img,x0,c0,x1,c1,x,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7X(img,x0,x1,x)
#define cimg_for_in7YZ(img,y0,z0,y1,z1,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7Y(img,y0,y1,y)
#define cimg_for_in7YC(img,y0,c0,y1,c1,y,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7Y(img,y0,y1,y)
#define cimg_for_in7ZC(img,z0,c0,z1,c1,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7Z(img,z0,z1,z)
#define cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7XY(img,x0,y0,x1,y1,x,y)
#define cimg_for_in7XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7XZ(img,x0,y0,x1,y1,x,z)
#define cimg_for_in7YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7YZ(img,y0,z0,y1,z1,y,z)
#define cimg_for_in7XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)

#define cimg_for8(bound,i) \
 for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
      _n1##i = 1>=(bound)?(int)(bound)-1:1, \
      _n2##i = 2>=(bound)?(int)(bound)-1:2, \
      _n3##i = 3>=(bound)?(int)(bound)-1:3, \
      _n4##i = 4>=(bound)?(int)(bound)-1:4; \
      _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
      i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
#define cimg_for8X(img,x) cimg_for8((img)._width,x)
#define cimg_for8Y(img,y) cimg_for8((img)._height,y)
#define cimg_for8Z(img,z) cimg_for8((img)._depth,z)
#define cimg_for8C(img,c) cimg_for8((img)._spectrum,c)
#define cimg_for8XY(img,x,y) cimg_for8Y(img,y) cimg_for8X(img,x)
#define cimg_for8XZ(img,x,z) cimg_for8Z(img,z) cimg_for8X(img,x)
#define cimg_for8XC(img,x,c) cimg_for8C(img,c) cimg_for8X(img,x)
#define cimg_for8YZ(img,y,z) cimg_for8Z(img,z) cimg_for8Y(img,y)
#define cimg_for8YC(img,y,c) cimg_for8C(img,c) cimg_for8Y(img,y)
#define cimg_for8ZC(img,z,c) cimg_for8C(img,c) cimg_for8Z(img,z)
#define cimg_for8XYZ(img,x,y,z) cimg_for8Z(img,z) cimg_for8XY(img,x,y)
#define cimg_for8XZC(img,x,z,c) cimg_for8C(img,c) cimg_for8XZ(img,x,z)
#define cimg_for8YZC(img,y,z,c) cimg_for8C(img,c) cimg_for8YZ(img,y,z)
#define cimg_for8XYZC(img,x,y,z,c) cimg_for8C(img,c) cimg_for8XYZ(img,x,y,z)

#define cimg_for_in8(bound,i0,i1,i) \
 for (int i = (int)(i0)<0?0:(int)(i0), \
      _p3##i = i-3<0?0:i-3, \
      _p2##i = i-2<0?0:i-2, \
      _p1##i = i-1<0?0:i-1, \
      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
      _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
      _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
      _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
      i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
      i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
#define cimg_for_in8X(img,x0,x1,x) cimg_for_in8((img)._width,x0,x1,x)
#define cimg_for_in8Y(img,y0,y1,y) cimg_for_in8((img)._height,y0,y1,y)
#define cimg_for_in8Z(img,z0,z1,z) cimg_for_in8((img)._depth,z0,z1,z)
#define cimg_for_in8C(img,c0,c1,c) cimg_for_in8((img)._spectrum,c0,c1,c)
#define cimg_for_in8XY(img,x0,y0,x1,y1,x,y) cimg_for_in8Y(img,y0,y1,y) cimg_for_in8X(img,x0,x1,x)
#define cimg_for_in8XZ(img,x0,z0,x1,z1,x,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8X(img,x0,x1,x)
#define cimg_for_in8XC(img,x0,c0,x1,c1,x,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8X(img,x0,x1,x)
#define cimg_for_in8YZ(img,y0,z0,y1,z1,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8Y(img,y0,y1,y)
#define cimg_for_in8YC(img,y0,c0,y1,c1,y,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8Y(img,y0,y1,y)
#define cimg_for_in8ZC(img,z0,c0,z1,c1,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8Z(img,z0,z1,z)
#define cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8XY(img,x0,y0,x1,y1,x,y)
#define cimg_for_in8XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8XZ(img,x0,y0,x1,y1,x,z)
#define cimg_for_in8YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8YZ(img,y0,z0,y1,z1,y,z)
#define cimg_for_in8XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)

#define cimg_for9(bound,i) \
  for (int i = 0, _p4##i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
       _n1##i = 1>=(int)(bound)?(int)(bound)-1:1, \
       _n2##i = 2>=(int)(bound)?(int)(bound)-1:2, \
       _n3##i = 3>=(int)(bound)?(int)(bound)-1:3, \
       _n4##i = 4>=(int)(bound)?(int)(bound)-1:4; \
       _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
       i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
       _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
#define cimg_for9X(img,x) cimg_for9((img)._width,x)
#define cimg_for9Y(img,y) cimg_for9((img)._height,y)
#define cimg_for9Z(img,z) cimg_for9((img)._depth,z)
#define cimg_for9C(img,c) cimg_for9((img)._spectrum,c)
#define cimg_for9XY(img,x,y) cimg_for9Y(img,y) cimg_for9X(img,x)
#define cimg_for9XZ(img,x,z) cimg_for9Z(img,z) cimg_for9X(img,x)
#define cimg_for9XC(img,x,c) cimg_for9C(img,c) cimg_for9X(img,x)
#define cimg_for9YZ(img,y,z) cimg_for9Z(img,z) cimg_for9Y(img,y)
#define cimg_for9YC(img,y,c) cimg_for9C(img,c) cimg_for9Y(img,y)
#define cimg_for9ZC(img,z,c) cimg_for9C(img,c) cimg_for9Z(img,z)
#define cimg_for9XYZ(img,x,y,z) cimg_for9Z(img,z) cimg_for9XY(img,x,y)
#define cimg_for9XZC(img,x,z,c) cimg_for9C(img,c) cimg_for9XZ(img,x,z)
#define cimg_for9YZC(img,y,z,c) cimg_for9C(img,c) cimg_for9YZ(img,y,z)
#define cimg_for9XYZC(img,x,y,z,c) cimg_for9C(img,c) cimg_for9XYZ(img,x,y,z)

#define cimg_for_in9(bound,i0,i1,i) \
  for (int i = (int)(i0)<0?0:(int)(i0), \
       _p4##i = i-4<0?0:i-4, \
       _p3##i = i-3<0?0:i-3, \
       _p2##i = i-2<0?0:i-2, \
       _p1##i = i-1<0?0:i-1, \
       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
       _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
       _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
       _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
       i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
       i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
       _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
#define cimg_for_in9X(img,x0,x1,x) cimg_for_in9((img)._width,x0,x1,x)
#define cimg_for_in9Y(img,y0,y1,y) cimg_for_in9((img)._height,y0,y1,y)
#define cimg_for_in9Z(img,z0,z1,z) cimg_for_in9((img)._depth,z0,z1,z)
#define cimg_for_in9C(img,c0,c1,c) cimg_for_in9((img)._spectrum,c0,c1,c)
#define cimg_for_in9XY(img,x0,y0,x1,y1,x,y) cimg_for_in9Y(img,y0,y1,y) cimg_for_in9X(img,x0,x1,x)
#define cimg_for_in9XZ(img,x0,z0,x1,z1,x,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9X(img,x0,x1,x)
#define cimg_for_in9XC(img,x0,c0,x1,c1,x,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9X(img,x0,x1,x)
#define cimg_for_in9YZ(img,y0,z0,y1,z1,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9Y(img,y0,y1,y)
#define cimg_for_in9YC(img,y0,c0,y1,c1,y,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9Y(img,y0,y1,y)
#define cimg_for_in9ZC(img,z0,c0,z1,c1,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9Z(img,z0,z1,z)
#define cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9XY(img,x0,y0,x1,y1,x,y)
#define cimg_for_in9XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9XZ(img,x0,y0,x1,y1,x,z)
#define cimg_for_in9YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9YZ(img,y0,z0,y1,z1,y,z)
#define cimg_for_in9XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)

#define cimg_for2x2(img,x,y,z,c,I,T) \
  cimg_for2((img)._height,y) for (int x = 0, \
   _n1##x = (int)( \
   (I[0] = (T)(img)(0,y,z,c)), \
   (I[2] = (T)(img)(0,_n1##y,z,c)), \
   1>=(img)._width?(img).width()-1:1);  \
   (_n1##x<(img).width() && ( \
   (I[1] = (T)(img)(_n1##x,y,z,c)), \
   (I[3] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \
   x==--_n1##x; \
   I[0] = I[1], \
   I[2] = I[3], \
   ++x, ++_n1##x)

#define cimg_for_in2x2(img,x0,y0,x1,y1,x,y,z,c,I,T) \
  cimg_for_in2((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
   _n1##x = (int)( \
   (I[0] = (T)(img)(x,y,z,c)), \
   (I[2] = (T)(img)(x,_n1##y,z,c)), \
   x+1>=(int)(img)._width?(img).width()-1:x+1); \
   x<=(int)(x1) && ((_n1##x<(img).width() && (  \
   (I[1] = (T)(img)(_n1##x,y,z,c)), \
   (I[3] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \
   x==--_n1##x); \
   I[0] = I[1], \
   I[2] = I[3], \
   ++x, ++_n1##x)

#define cimg_for3x3(img,x,y,z,c,I,T) \
  cimg_for3((img)._height,y) for (int x = 0, \
   _p1##x = 0, \
   _n1##x = (int)( \
   (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \
   (I[3] = I[4] = (T)(img)(0,y,z,c)), \
   (I[6] = I[7] = (T)(img)(0,_n1##y,z,c)),      \
   1>=(img)._width?(img).width()-1:1); \
   (_n1##x<(img).width() && ( \
   (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[5] = (T)(img)(_n1##x,y,z,c)), \
   (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \
   x==--_n1##x; \
   I[0] = I[1], I[1] = I[2], \
   I[3] = I[4], I[4] = I[5], \
   I[6] = I[7], I[7] = I[8], \
   _p1##x = x++, ++_n1##x)

#define cimg_for_in3x3(img,x0,y0,x1,y1,x,y,z,c,I,T) \
  cimg_for_in3((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
   _p1##x = x-1<0?0:x-1, \
   _n1##x = (int)( \
   (I[0] = (T)(img)(_p1##x,_p1##y,z,c)), \
   (I[3] = (T)(img)(_p1##x,y,z,c)), \
   (I[6] = (T)(img)(_p1##x,_n1##y,z,c)), \
   (I[1] = (T)(img)(x,_p1##y,z,c)), \
   (I[4] = (T)(img)(x,y,z,c)), \
   (I[7] = (T)(img)(x,_n1##y,z,c)), \
   x+1>=(int)(img)._width?(img).width()-1:x+1); \
   x<=(int)(x1) && ((_n1##x<(img).width() && ( \
   (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[5] = (T)(img)(_n1##x,y,z,c)), \
   (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \
   x==--_n1##x);            \
   I[0] = I[1], I[1] = I[2], \
   I[3] = I[4], I[4] = I[5], \
   I[6] = I[7], I[7] = I[8], \
   _p1##x = x++, ++_n1##x)

#define cimg_for4x4(img,x,y,z,c,I,T) \
  cimg_for4((img)._height,y) for (int x = 0, \
   _p1##x = 0, \
   _n1##x = 1>=(img)._width?(img).width()-1:1, \
   _n2##x = (int)( \
   (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \
   (I[4] = I[5] = (T)(img)(0,y,z,c)), \
   (I[8] = I[9] = (T)(img)(0,_n1##y,z,c)), \
   (I[12] = I[13] = (T)(img)(0,_n2##y,z,c)), \
   (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[6] = (T)(img)(_n1##x,y,z,c)), \
   (I[10] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[14] = (T)(img)(_n1##x,_n2##y,z,c)), \
   2>=(img)._width?(img).width()-1:2); \
   (_n2##x<(img).width() && ( \
   (I[3] = (T)(img)(_n2##x,_p1##y,z,c)), \
   (I[7] = (T)(img)(_n2##x,y,z,c)), \
   (I[11] = (T)(img)(_n2##x,_n1##y,z,c)), \
   (I[15] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \
   _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
   I[0] = I[1], I[1] = I[2], I[2] = I[3], \
   I[4] = I[5], I[5] = I[6], I[6] = I[7], \
   I[8] = I[9], I[9] = I[10], I[10] = I[11], \
   I[12] = I[13], I[13] = I[14], I[14] = I[15], \
   _p1##x = x++, ++_n1##x, ++_n2##x)

#define cimg_for_in4x4(img,x0,y0,x1,y1,x,y,z,c,I,T) \
  cimg_for_in4((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
   _p1##x = x-1<0?0:x-1, \
   _n1##x = x+1>=(int)(img)._width?(img).width()-1:x+1, \
   _n2##x = (int)( \
   (I[0] = (T)(img)(_p1##x,_p1##y,z,c)), \
   (I[4] = (T)(img)(_p1##x,y,z,c)), \
   (I[8] = (T)(img)(_p1##x,_n1##y,z,c)), \
   (I[12] = (T)(img)(_p1##x,_n2##y,z,c)), \
   (I[1] = (T)(img)(x,_p1##y,z,c)), \
   (I[5] = (T)(img)(x,y,z,c)), \
   (I[9] = (T)(img)(x,_n1##y,z,c)), \
   (I[13] = (T)(img)(x,_n2##y,z,c)), \
   (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[6] = (T)(img)(_n1##x,y,z,c)), \
   (I[10] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[14] = (T)(img)(_n1##x,_n2##y,z,c)), \
   x+2>=(int)(img)._width?(img).width()-1:x+2); \
   x<=(int)(x1) && ((_n2##x<(img).width() && ( \
   (I[3] = (T)(img)(_n2##x,_p1##y,z,c)), \
   (I[7] = (T)(img)(_n2##x,y,z,c)), \
   (I[11] = (T)(img)(_n2##x,_n1##y,z,c)), \
   (I[15] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \
   _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
   I[0] = I[1], I[1] = I[2], I[2] = I[3], \
   I[4] = I[5], I[5] = I[6], I[6] = I[7], \
   I[8] = I[9], I[9] = I[10], I[10] = I[11], \
   I[12] = I[13], I[13] = I[14], I[14] = I[15], \
   _p1##x = x++, ++_n1##x, ++_n2##x)

#define cimg_for5x5(img,x,y,z,c,I,T) \
 cimg_for5((img)._height,y) for (int x = 0, \
   _p2##x = 0, _p1##x = 0, \
   _n1##x = 1>=(img)._width?(img).width()-1:1, \
   _n2##x = (int)( \
   (I[0] = I[1] = I[2] = (T)(img)(_p2##x,_p2##y,z,c)), \
   (I[5] = I[6] = I[7] = (T)(img)(0,_p1##y,z,c)), \
   (I[10] = I[11] = I[12] = (T)(img)(0,y,z,c)), \
   (I[15] = I[16] = I[17] = (T)(img)(0,_n1##y,z,c)), \
   (I[20] = I[21] = I[22] = (T)(img)(0,_n2##y,z,c)), \
   (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \
   (I[8] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[13] = (T)(img)(_n1##x,y,z,c)), \
   (I[18] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[23] = (T)(img)(_n1##x,_n2##y,z,c)),  \
   2>=(img)._width?(img).width()-1:2); \
   (_n2##x<(img).width() && ( \
   (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \
   (I[9] = (T)(img)(_n2##x,_p1##y,z,c)), \
   (I[14] = (T)(img)(_n2##x,y,z,c)), \
   (I[19] = (T)(img)(_n2##x,_n1##y,z,c)), \
   (I[24] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \
   _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
   I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
   I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
   I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
   I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)

#define cimg_for_in5x5(img,x0,y0,x1,y1,x,y,z,c,I,T) \
 cimg_for_in5((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
   _p2##x = x-2<0?0:x-2, \
   _p1##x = x-1<0?0:x-1, \
   _n1##x = x+1>=(int)(img)._width?(img).width()-1:x+1, \
   _n2##x = (int)( \
   (I[0] = (T)(img)(_p2##x,_p2##y,z,c)), \
   (I[5] = (T)(img)(_p2##x,_p1##y,z,c)), \
   (I[10] = (T)(img)(_p2##x,y,z,c)), \
   (I[15] = (T)(img)(_p2##x,_n1##y,z,c)), \
   (I[20] = (T)(img)(_p2##x,_n2##y,z,c)), \
   (I[1] = (T)(img)(_p1##x,_p2##y,z,c)), \
   (I[6] = (T)(img)(_p1##x,_p1##y,z,c)), \
   (I[11] = (T)(img)(_p1##x,y,z,c)), \
   (I[16] = (T)(img)(_p1##x,_n1##y,z,c)), \
   (I[21] = (T)(img)(_p1##x,_n2##y,z,c)), \
   (I[2] = (T)(img)(x,_p2##y,z,c)), \
   (I[7] = (T)(img)(x,_p1##y,z,c)), \
   (I[12] = (T)(img)(x,y,z,c)), \
   (I[17] = (T)(img)(x,_n1##y,z,c)), \
   (I[22] = (T)(img)(x,_n2##y,z,c)), \
   (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \
   (I[8] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[13] = (T)(img)(_n1##x,y,z,c)), \
   (I[18] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[23] = (T)(img)(_n1##x,_n2##y,z,c)), \
   x+2>=(int)(img)._width?(img).width()-1:x+2); \
   x<=(int)(x1) && ((_n2##x<(img).width() && ( \
   (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \
   (I[9] = (T)(img)(_n2##x,_p1##y,z,c)), \
   (I[14] = (T)(img)(_n2##x,y,z,c)), \
   (I[19] = (T)(img)(_n2##x,_n1##y,z,c)), \
   (I[24] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \
   _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
   I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
   I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
   I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
   I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)

#define cimg_for6x6(img,x,y,z,c,I,T) \
 cimg_for6((img)._height,y) for (int x = 0, \
   _p2##x = 0, _p1##x = 0, \
   _n1##x = 1>=(img)._width?(img).width()-1:1, \
   _n2##x = 2>=(img)._width?(img).width()-1:2, \
   _n3##x = (int)( \
   (I[0] = I[1] = I[2] = (T)(img)(_p2##x,_p2##y,z,c)), \
   (I[6] = I[7] = I[8] = (T)(img)(0,_p1##y,z,c)), \
   (I[12] = I[13] = I[14] = (T)(img)(0,y,z,c)), \
   (I[18] = I[19] = I[20] = (T)(img)(0,_n1##y,z,c)), \
   (I[24] = I[25] = I[26] = (T)(img)(0,_n2##y,z,c)), \
   (I[30] = I[31] = I[32] = (T)(img)(0,_n3##y,z,c)), \
   (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \
   (I[9] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[15] = (T)(img)(_n1##x,y,z,c)), \
   (I[21] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[27] = (T)(img)(_n1##x,_n2##y,z,c)), \
   (I[33] = (T)(img)(_n1##x,_n3##y,z,c)), \
   (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \
   (I[10] = (T)(img)(_n2##x,_p1##y,z,c)), \
   (I[16] = (T)(img)(_n2##x,y,z,c)), \
   (I[22] = (T)(img)(_n2##x,_n1##y,z,c)), \
   (I[28] = (T)(img)(_n2##x,_n2##y,z,c)), \
   (I[34] = (T)(img)(_n2##x,_n3##y,z,c)), \
   3>=(img)._width?(img).width()-1:3); \
   (_n3##x<(img).width() && ( \
   (I[5] = (T)(img)(_n3##x,_p2##y,z,c)), \
   (I[11] = (T)(img)(_n3##x,_p1##y,z,c)), \
   (I[17] = (T)(img)(_n3##x,y,z,c)), \
   (I[23] = (T)(img)(_n3##x,_n1##y,z,c)), \
   (I[29] = (T)(img)(_n3##x,_n2##y,z,c)), \
   (I[35] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \
   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x); \
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
   I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
   I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
   I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
   I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
   I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)

#define cimg_for_in6x6(img,x0,y0,x1,y1,x,y,z,c,I,T) \
  cimg_for_in6((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)x0, \
   _p2##x = x-2<0?0:x-2, \
   _p1##x = x-1<0?0:x-1, \
   _n1##x = x+1>=(int)(img)._width?(img).width()-1:x+1, \
   _n2##x = x+2>=(int)(img)._width?(img).width()-1:x+2, \
   _n3##x = (int)( \
   (I[0] = (T)(img)(_p2##x,_p2##y,z,c)), \
   (I[6] = (T)(img)(_p2##x,_p1##y,z,c)), \
   (I[12] = (T)(img)(_p2##x,y,z,c)), \
   (I[18] = (T)(img)(_p2##x,_n1##y,z,c)), \
   (I[24] = (T)(img)(_p2##x,_n2##y,z,c)), \
   (I[30] = (T)(img)(_p2##x,_n3##y,z,c)), \
   (I[1] = (T)(img)(_p1##x,_p2##y,z,c)), \
   (I[7] = (T)(img)(_p1##x,_p1##y,z,c)), \
   (I[13] = (T)(img)(_p1##x,y,z,c)), \
   (I[19] = (T)(img)(_p1##x,_n1##y,z,c)), \
   (I[25] = (T)(img)(_p1##x,_n2##y,z,c)), \
   (I[31] = (T)(img)(_p1##x,_n3##y,z,c)), \
   (I[2] = (T)(img)(x,_p2##y,z,c)), \
   (I[8] = (T)(img)(x,_p1##y,z,c)), \
   (I[14] = (T)(img)(x,y,z,c)), \
   (I[20] = (T)(img)(x,_n1##y,z,c)), \
   (I[26] = (T)(img)(x,_n2##y,z,c)), \
   (I[32] = (T)(img)(x,_n3##y,z,c)), \
   (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \
   (I[9] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[15] = (T)(img)(_n1##x,y,z,c)), \
   (I[21] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[27] = (T)(img)(_n1##x,_n2##y,z,c)), \
   (I[33] = (T)(img)(_n1##x,_n3##y,z,c)), \
   (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \
   (I[10] = (T)(img)(_n2##x,_p1##y,z,c)), \
   (I[16] = (T)(img)(_n2##x,y,z,c)), \
   (I[22] = (T)(img)(_n2##x,_n1##y,z,c)), \
   (I[28] = (T)(img)(_n2##x,_n2##y,z,c)), \
   (I[34] = (T)(img)(_n2##x,_n3##y,z,c)), \
   x+3>=(int)(img)._width?(img).width()-1:x+3); \
   x<=(int)(x1) && ((_n3##x<(img).width() && ( \
   (I[5] = (T)(img)(_n3##x,_p2##y,z,c)), \
   (I[11] = (T)(img)(_n3##x,_p1##y,z,c)), \
   (I[17] = (T)(img)(_n3##x,y,z,c)), \
   (I[23] = (T)(img)(_n3##x,_n1##y,z,c)), \
   (I[29] = (T)(img)(_n3##x,_n2##y,z,c)), \
   (I[35] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \
   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x)); \
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
   I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
   I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
   I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
   I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
   I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)

#define cimg_for7x7(img,x,y,z,c,I,T) \
  cimg_for7((img)._height,y) for (int x = 0, \
   _p3##x = 0, _p2##x = 0, _p1##x = 0, \
   _n1##x = 1>=(img)._width?(img).width()-1:1, \
   _n2##x = 2>=(img)._width?(img).width()-1:2, \
   _n3##x = (int)( \
   (I[0] = I[1] = I[2] = I[3] = (T)(img)(_p3##x,_p3##y,z,c)), \
   (I[7] = I[8] = I[9] = I[10] = (T)(img)(0,_p2##y,z,c)), \
   (I[14] = I[15] = I[16] = I[17] = (T)(img)(0,_p1##y,z,c)), \
   (I[21] = I[22] = I[23] = I[24] = (T)(img)(0,y,z,c)), \
   (I[28] = I[29] = I[30] = I[31] = (T)(img)(0,_n1##y,z,c)), \
   (I[35] = I[36] = I[37] = I[38] = (T)(img)(0,_n2##y,z,c)), \
   (I[42] = I[43] = I[44] = I[45] = (T)(img)(0,_n3##y,z,c)), \
   (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \
   (I[11] = (T)(img)(_n1##x,_p2##y,z,c)), \
   (I[18] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[25] = (T)(img)(_n1##x,y,z,c)), \
   (I[32] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[39] = (T)(img)(_n1##x,_n2##y,z,c)), \
   (I[46] = (T)(img)(_n1##x,_n3##y,z,c)), \
   (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \
   (I[12] = (T)(img)(_n2##x,_p2##y,z,c)), \
   (I[19] = (T)(img)(_n2##x,_p1##y,z,c)), \
   (I[26] = (T)(img)(_n2##x,y,z,c)), \
   (I[33] = (T)(img)(_n2##x,_n1##y,z,c)), \
   (I[40] = (T)(img)(_n2##x,_n2##y,z,c)), \
   (I[47] = (T)(img)(_n2##x,_n3##y,z,c)), \
   3>=(img)._width?(img).width()-1:3); \
   (_n3##x<(img).width() && ( \
   (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \
   (I[13] = (T)(img)(_n3##x,_p2##y,z,c)), \
   (I[20] = (T)(img)(_n3##x,_p1##y,z,c)), \
   (I[27] = (T)(img)(_n3##x,y,z,c)), \
   (I[34] = (T)(img)(_n3##x,_n1##y,z,c)), \
   (I[41] = (T)(img)(_n3##x,_n2##y,z,c)), \
   (I[48] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \
   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x); \
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
   I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
   I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
   I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
   I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
   I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
   I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)

#define cimg_for_in7x7(img,x0,y0,x1,y1,x,y,z,c,I,T) \
  cimg_for_in7((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
   _p3##x = x-3<0?0:x-3, \
   _p2##x = x-2<0?0:x-2, \
   _p1##x = x-1<0?0:x-1, \
   _n1##x = x+1>=(int)(img)._width?(img).width()-1:x+1, \
   _n2##x = x+2>=(int)(img)._width?(img).width()-1:x+2, \
   _n3##x = (int)( \
   (I[0] = (T)(img)(_p3##x,_p3##y,z,c)), \
   (I[7] = (T)(img)(_p3##x,_p2##y,z,c)), \
   (I[14] = (T)(img)(_p3##x,_p1##y,z,c)), \
   (I[21] = (T)(img)(_p3##x,y,z,c)), \
   (I[28] = (T)(img)(_p3##x,_n1##y,z,c)), \
   (I[35] = (T)(img)(_p3##x,_n2##y,z,c)), \
   (I[42] = (T)(img)(_p3##x,_n3##y,z,c)), \
   (I[1] = (T)(img)(_p2##x,_p3##y,z,c)), \
   (I[8] = (T)(img)(_p2##x,_p2##y,z,c)), \
   (I[15] = (T)(img)(_p2##x,_p1##y,z,c)), \
   (I[22] = (T)(img)(_p2##x,y,z,c)), \
   (I[29] = (T)(img)(_p2##x,_n1##y,z,c)), \
   (I[36] = (T)(img)(_p2##x,_n2##y,z,c)), \
   (I[43] = (T)(img)(_p2##x,_n3##y,z,c)), \
   (I[2] = (T)(img)(_p1##x,_p3##y,z,c)), \
   (I[9] = (T)(img)(_p1##x,_p2##y,z,c)), \
   (I[16] = (T)(img)(_p1##x,_p1##y,z,c)), \
   (I[23] = (T)(img)(_p1##x,y,z,c)), \
   (I[30] = (T)(img)(_p1##x,_n1##y,z,c)), \
   (I[37] = (T)(img)(_p1##x,_n2##y,z,c)), \
   (I[44] = (T)(img)(_p1##x,_n3##y,z,c)), \
   (I[3] = (T)(img)(x,_p3##y,z,c)), \
   (I[10] = (T)(img)(x,_p2##y,z,c)), \
   (I[17] = (T)(img)(x,_p1##y,z,c)), \
   (I[24] = (T)(img)(x,y,z,c)), \
   (I[31] = (T)(img)(x,_n1##y,z,c)), \
   (I[38] = (T)(img)(x,_n2##y,z,c)), \
   (I[45] = (T)(img)(x,_n3##y,z,c)), \
   (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \
   (I[11] = (T)(img)(_n1##x,_p2##y,z,c)), \
   (I[18] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[25] = (T)(img)(_n1##x,y,z,c)), \
   (I[32] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[39] = (T)(img)(_n1##x,_n2##y,z,c)), \
   (I[46] = (T)(img)(_n1##x,_n3##y,z,c)), \
   (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \
   (I[12] = (T)(img)(_n2##x,_p2##y,z,c)), \
   (I[19] = (T)(img)(_n2##x,_p1##y,z,c)), \
   (I[26] = (T)(img)(_n2##x,y,z,c)), \
   (I[33] = (T)(img)(_n2##x,_n1##y,z,c)), \
   (I[40] = (T)(img)(_n2##x,_n2##y,z,c)), \
   (I[47] = (T)(img)(_n2##x,_n3##y,z,c)), \
   x+3>=(int)(img)._width?(img).width()-1:x+3); \
   x<=(int)(x1) && ((_n3##x<(img).width() && ( \
   (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \
   (I[13] = (T)(img)(_n3##x,_p2##y,z,c)), \
   (I[20] = (T)(img)(_n3##x,_p1##y,z,c)), \
   (I[27] = (T)(img)(_n3##x,y,z,c)), \
   (I[34] = (T)(img)(_n3##x,_n1##y,z,c)), \
   (I[41] = (T)(img)(_n3##x,_n2##y,z,c)), \
   (I[48] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \
   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x)); \
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
   I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
   I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
   I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
   I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
   I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
   I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)

#define cimg_for8x8(img,x,y,z,c,I,T) \
  cimg_for8((img)._height,y) for (int x = 0, \
   _p3##x = 0, _p2##x = 0, _p1##x = 0, \
   _n1##x = 1>=((img)._width)?(img).width()-1:1, \
   _n2##x = 2>=((img)._width)?(img).width()-1:2, \
   _n3##x = 3>=((img)._width)?(img).width()-1:3, \
   _n4##x = (int)( \
   (I[0] = I[1] = I[2] = I[3] = (T)(img)(_p3##x,_p3##y,z,c)), \
   (I[8] = I[9] = I[10] = I[11] = (T)(img)(0,_p2##y,z,c)), \
   (I[16] = I[17] = I[18] = I[19] = (T)(img)(0,_p1##y,z,c)), \
   (I[24] = I[25] = I[26] = I[27] = (T)(img)(0,y,z,c)), \
   (I[32] = I[33] = I[34] = I[35] = (T)(img)(0,_n1##y,z,c)), \
   (I[40] = I[41] = I[42] = I[43] = (T)(img)(0,_n2##y,z,c)), \
   (I[48] = I[49] = I[50] = I[51] = (T)(img)(0,_n3##y,z,c)), \
   (I[56] = I[57] = I[58] = I[59] = (T)(img)(0,_n4##y,z,c)), \
   (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \
   (I[12] = (T)(img)(_n1##x,_p2##y,z,c)), \
   (I[20] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[28] = (T)(img)(_n1##x,y,z,c)), \
   (I[36] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[44] = (T)(img)(_n1##x,_n2##y,z,c)), \
   (I[52] = (T)(img)(_n1##x,_n3##y,z,c)), \
   (I[60] = (T)(img)(_n1##x,_n4##y,z,c)), \
   (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \
   (I[13] = (T)(img)(_n2##x,_p2##y,z,c)), \
   (I[21] = (T)(img)(_n2##x,_p1##y,z,c)), \
   (I[29] = (T)(img)(_n2##x,y,z,c)), \
   (I[37] = (T)(img)(_n2##x,_n1##y,z,c)), \
   (I[45] = (T)(img)(_n2##x,_n2##y,z,c)), \
   (I[53] = (T)(img)(_n2##x,_n3##y,z,c)), \
   (I[61] = (T)(img)(_n2##x,_n4##y,z,c)), \
   (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \
   (I[14] = (T)(img)(_n3##x,_p2##y,z,c)), \
   (I[22] = (T)(img)(_n3##x,_p1##y,z,c)), \
   (I[30] = (T)(img)(_n3##x,y,z,c)), \
   (I[38] = (T)(img)(_n3##x,_n1##y,z,c)), \
   (I[46] = (T)(img)(_n3##x,_n2##y,z,c)), \
   (I[54] = (T)(img)(_n3##x,_n3##y,z,c)), \
   (I[62] = (T)(img)(_n3##x,_n4##y,z,c)), \
   4>=((img)._width)?(img).width()-1:4); \
   (_n4##x<(img).width() && ( \
   (I[7] = (T)(img)(_n4##x,_p3##y,z,c)), \
   (I[15] = (T)(img)(_n4##x,_p2##y,z,c)), \
   (I[23] = (T)(img)(_n4##x,_p1##y,z,c)), \
   (I[31] = (T)(img)(_n4##x,y,z,c)), \
   (I[39] = (T)(img)(_n4##x,_n1##y,z,c)), \
   (I[47] = (T)(img)(_n4##x,_n2##y,z,c)), \
   (I[55] = (T)(img)(_n4##x,_n3##y,z,c)), \
   (I[63] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \
   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \
   I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \
   I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
   I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \
   I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \
   I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \
   I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \
   I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \
   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)

#define cimg_for_in8x8(img,x0,y0,x1,y1,x,y,z,c,I,T) \
  cimg_for_in8((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
   _p3##x = x-3<0?0:x-3, \
   _p2##x = x-2<0?0:x-2, \
   _p1##x = x-1<0?0:x-1, \
   _n1##x = x+1>=(img).width()?(img).width()-1:x+1, \
   _n2##x = x+2>=(img).width()?(img).width()-1:x+2, \
   _n3##x = x+3>=(img).width()?(img).width()-1:x+3, \
   _n4##x = (int)( \
   (I[0] = (T)(img)(_p3##x,_p3##y,z,c)), \
   (I[8] = (T)(img)(_p3##x,_p2##y,z,c)), \
   (I[16] = (T)(img)(_p3##x,_p1##y,z,c)), \
   (I[24] = (T)(img)(_p3##x,y,z,c)), \
   (I[32] = (T)(img)(_p3##x,_n1##y,z,c)), \
   (I[40] = (T)(img)(_p3##x,_n2##y,z,c)), \
   (I[48] = (T)(img)(_p3##x,_n3##y,z,c)), \
   (I[56] = (T)(img)(_p3##x,_n4##y,z,c)), \
   (I[1] = (T)(img)(_p2##x,_p3##y,z,c)), \
   (I[9] = (T)(img)(_p2##x,_p2##y,z,c)), \
   (I[17] = (T)(img)(_p2##x,_p1##y,z,c)), \
   (I[25] = (T)(img)(_p2##x,y,z,c)), \
   (I[33] = (T)(img)(_p2##x,_n1##y,z,c)), \
   (I[41] = (T)(img)(_p2##x,_n2##y,z,c)), \
   (I[49] = (T)(img)(_p2##x,_n3##y,z,c)), \
   (I[57] = (T)(img)(_p2##x,_n4##y,z,c)), \
   (I[2] = (T)(img)(_p1##x,_p3##y,z,c)), \
   (I[10] = (T)(img)(_p1##x,_p2##y,z,c)), \
   (I[18] = (T)(img)(_p1##x,_p1##y,z,c)), \
   (I[26] = (T)(img)(_p1##x,y,z,c)), \
   (I[34] = (T)(img)(_p1##x,_n1##y,z,c)), \
   (I[42] = (T)(img)(_p1##x,_n2##y,z,c)), \
   (I[50] = (T)(img)(_p1##x,_n3##y,z,c)), \
   (I[58] = (T)(img)(_p1##x,_n4##y,z,c)), \
   (I[3] = (T)(img)(x,_p3##y,z,c)), \
   (I[11] = (T)(img)(x,_p2##y,z,c)), \
   (I[19] = (T)(img)(x,_p1##y,z,c)), \
   (I[27] = (T)(img)(x,y,z,c)), \
   (I[35] = (T)(img)(x,_n1##y,z,c)), \
   (I[43] = (T)(img)(x,_n2##y,z,c)), \
   (I[51] = (T)(img)(x,_n3##y,z,c)), \
   (I[59] = (T)(img)(x,_n4##y,z,c)), \
   (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \
   (I[12] = (T)(img)(_n1##x,_p2##y,z,c)), \
   (I[20] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[28] = (T)(img)(_n1##x,y,z,c)), \
   (I[36] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[44] = (T)(img)(_n1##x,_n2##y,z,c)), \
   (I[52] = (T)(img)(_n1##x,_n3##y,z,c)), \
   (I[60] = (T)(img)(_n1##x,_n4##y,z,c)), \
   (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \
   (I[13] = (T)(img)(_n2##x,_p2##y,z,c)), \
   (I[21] = (T)(img)(_n2##x,_p1##y,z,c)), \
   (I[29] = (T)(img)(_n2##x,y,z,c)), \
   (I[37] = (T)(img)(_n2##x,_n1##y,z,c)), \
   (I[45] = (T)(img)(_n2##x,_n2##y,z,c)), \
   (I[53] = (T)(img)(_n2##x,_n3##y,z,c)), \
   (I[61] = (T)(img)(_n2##x,_n4##y,z,c)), \
   (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \
   (I[14] = (T)(img)(_n3##x,_p2##y,z,c)), \
   (I[22] = (T)(img)(_n3##x,_p1##y,z,c)), \
   (I[30] = (T)(img)(_n3##x,y,z,c)), \
   (I[38] = (T)(img)(_n3##x,_n1##y,z,c)), \
   (I[46] = (T)(img)(_n3##x,_n2##y,z,c)), \
   (I[54] = (T)(img)(_n3##x,_n3##y,z,c)), \
   (I[62] = (T)(img)(_n3##x,_n4##y,z,c)), \
   x+4>=(img).width()?(img).width()-1:x+4); \
   x<=(int)(x1) && ((_n4##x<(img).width() && ( \
   (I[7] = (T)(img)(_n4##x,_p3##y,z,c)), \
   (I[15] = (T)(img)(_n4##x,_p2##y,z,c)), \
   (I[23] = (T)(img)(_n4##x,_p1##y,z,c)), \
   (I[31] = (T)(img)(_n4##x,y,z,c)), \
   (I[39] = (T)(img)(_n4##x,_n1##y,z,c)), \
   (I[47] = (T)(img)(_n4##x,_n2##y,z,c)), \
   (I[55] = (T)(img)(_n4##x,_n3##y,z,c)), \
   (I[63] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \
   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \
   I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \
   I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
   I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \
   I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \
   I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \
   I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \
   I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \
   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)

#define cimg_for9x9(img,x,y,z,c,I,T) \
  cimg_for9((img)._height,y) for (int x = 0, \
   _p4##x = 0, _p3##x = 0, _p2##x = 0, _p1##x = 0, \
   _n1##x = 1>=((img)._width)?(img).width()-1:1, \
   _n2##x = 2>=((img)._width)?(img).width()-1:2, \
   _n3##x = 3>=((img)._width)?(img).width()-1:3, \
   _n4##x = (int)( \
   (I[0] = I[1] = I[2] = I[3] = I[4] = (T)(img)(_p4##x,_p4##y,z,c)), \
   (I[9] = I[10] = I[11] = I[12] = I[13] = (T)(img)(0,_p3##y,z,c)), \
   (I[18] = I[19] = I[20] = I[21] = I[22] = (T)(img)(0,_p2##y,z,c)), \
   (I[27] = I[28] = I[29] = I[30] = I[31] = (T)(img)(0,_p1##y,z,c)), \
   (I[36] = I[37] = I[38] = I[39] = I[40] = (T)(img)(0,y,z,c)), \
   (I[45] = I[46] = I[47] = I[48] = I[49] = (T)(img)(0,_n1##y,z,c)), \
   (I[54] = I[55] = I[56] = I[57] = I[58] = (T)(img)(0,_n2##y,z,c)), \
   (I[63] = I[64] = I[65] = I[66] = I[67] = (T)(img)(0,_n3##y,z,c)), \
   (I[72] = I[73] = I[74] = I[75] = I[76] = (T)(img)(0,_n4##y,z,c)), \
   (I[5] = (T)(img)(_n1##x,_p4##y,z,c)), \
   (I[14] = (T)(img)(_n1##x,_p3##y,z,c)), \
   (I[23] = (T)(img)(_n1##x,_p2##y,z,c)), \
   (I[32] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[41] = (T)(img)(_n1##x,y,z,c)), \
   (I[50] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[59] = (T)(img)(_n1##x,_n2##y,z,c)), \
   (I[68] = (T)(img)(_n1##x,_n3##y,z,c)), \
   (I[77] = (T)(img)(_n1##x,_n4##y,z,c)), \
   (I[6] = (T)(img)(_n2##x,_p4##y,z,c)), \
   (I[15] = (T)(img)(_n2##x,_p3##y,z,c)), \
   (I[24] = (T)(img)(_n2##x,_p2##y,z,c)), \
   (I[33] = (T)(img)(_n2##x,_p1##y,z,c)), \
   (I[42] = (T)(img)(_n2##x,y,z,c)), \
   (I[51] = (T)(img)(_n2##x,_n1##y,z,c)), \
   (I[60] = (T)(img)(_n2##x,_n2##y,z,c)), \
   (I[69] = (T)(img)(_n2##x,_n3##y,z,c)), \
   (I[78] = (T)(img)(_n2##x,_n4##y,z,c)), \
   (I[7] = (T)(img)(_n3##x,_p4##y,z,c)), \
   (I[16] = (T)(img)(_n3##x,_p3##y,z,c)), \
   (I[25] = (T)(img)(_n3##x,_p2##y,z,c)), \
   (I[34] = (T)(img)(_n3##x,_p1##y,z,c)), \
   (I[43] = (T)(img)(_n3##x,y,z,c)), \
   (I[52] = (T)(img)(_n3##x,_n1##y,z,c)), \
   (I[61] = (T)(img)(_n3##x,_n2##y,z,c)), \
   (I[70] = (T)(img)(_n3##x,_n3##y,z,c)), \
   (I[79] = (T)(img)(_n3##x,_n4##y,z,c)), \
   4>=((img)._width)?(img).width()-1:4); \
   (_n4##x<(img).width() && ( \
   (I[8] = (T)(img)(_n4##x,_p4##y,z,c)), \
   (I[17] = (T)(img)(_n4##x,_p3##y,z,c)), \
   (I[26] = (T)(img)(_n4##x,_p2##y,z,c)), \
   (I[35] = (T)(img)(_n4##x,_p1##y,z,c)), \
   (I[44] = (T)(img)(_n4##x,y,z,c)), \
   (I[53] = (T)(img)(_n4##x,_n1##y,z,c)), \
   (I[62] = (T)(img)(_n4##x,_n2##y,z,c)), \
   (I[71] = (T)(img)(_n4##x,_n3##y,z,c)), \
   (I[80] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \
   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \
   I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
   I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], \
   I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
   I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], \
   I[45] = I[46], I[46] = I[47], I[47] = I[48], I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], \
   I[54] = I[55], I[55] = I[56], I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], \
   I[63] = I[64], I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \
   I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], I[79] = I[80], \
   _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)

#define cimg_for_in9x9(img,x0,y0,x1,y1,x,y,z,c,I,T) \
  cimg_for_in9((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
   _p4##x = x-4<0?0:x-4, \
   _p3##x = x-3<0?0:x-3, \
   _p2##x = x-2<0?0:x-2, \
   _p1##x = x-1<0?0:x-1, \
   _n1##x = x+1>=(img).width()?(img).width()-1:x+1, \
   _n2##x = x+2>=(img).width()?(img).width()-1:x+2, \
   _n3##x = x+3>=(img).width()?(img).width()-1:x+3, \
   _n4##x = (int)( \
   (I[0] = (T)(img)(_p4##x,_p4##y,z,c)), \
   (I[9] = (T)(img)(_p4##x,_p3##y,z,c)), \
   (I[18] = (T)(img)(_p4##x,_p2##y,z,c)), \
   (I[27] = (T)(img)(_p4##x,_p1##y,z,c)), \
   (I[36] = (T)(img)(_p4##x,y,z,c)), \
   (I[45] = (T)(img)(_p4##x,_n1##y,z,c)), \
   (I[54] = (T)(img)(_p4##x,_n2##y,z,c)), \
   (I[63] = (T)(img)(_p4##x,_n3##y,z,c)), \
   (I[72] = (T)(img)(_p4##x,_n4##y,z,c)), \
   (I[1] = (T)(img)(_p3##x,_p4##y,z,c)), \
   (I[10] = (T)(img)(_p3##x,_p3##y,z,c)), \
   (I[19] = (T)(img)(_p3##x,_p2##y,z,c)), \
   (I[28] = (T)(img)(_p3##x,_p1##y,z,c)), \
   (I[37] = (T)(img)(_p3##x,y,z,c)), \
   (I[46] = (T)(img)(_p3##x,_n1##y,z,c)), \
   (I[55] = (T)(img)(_p3##x,_n2##y,z,c)), \
   (I[64] = (T)(img)(_p3##x,_n3##y,z,c)), \
   (I[73] = (T)(img)(_p3##x,_n4##y,z,c)), \
   (I[2] = (T)(img)(_p2##x,_p4##y,z,c)), \
   (I[11] = (T)(img)(_p2##x,_p3##y,z,c)), \
   (I[20] = (T)(img)(_p2##x,_p2##y,z,c)), \
   (I[29] = (T)(img)(_p2##x,_p1##y,z,c)), \
   (I[38] = (T)(img)(_p2##x,y,z,c)), \
   (I[47] = (T)(img)(_p2##x,_n1##y,z,c)), \
   (I[56] = (T)(img)(_p2##x,_n2##y,z,c)), \
   (I[65] = (T)(img)(_p2##x,_n3##y,z,c)), \
   (I[74] = (T)(img)(_p2##x,_n4##y,z,c)), \
   (I[3] = (T)(img)(_p1##x,_p4##y,z,c)), \
   (I[12] = (T)(img)(_p1##x,_p3##y,z,c)), \
   (I[21] = (T)(img)(_p1##x,_p2##y,z,c)), \
   (I[30] = (T)(img)(_p1##x,_p1##y,z,c)), \
   (I[39] = (T)(img)(_p1##x,y,z,c)), \
   (I[48] = (T)(img)(_p1##x,_n1##y,z,c)), \
   (I[57] = (T)(img)(_p1##x,_n2##y,z,c)), \
   (I[66] = (T)(img)(_p1##x,_n3##y,z,c)), \
   (I[75] = (T)(img)(_p1##x,_n4##y,z,c)), \
   (I[4] = (T)(img)(x,_p4##y,z,c)), \
   (I[13] = (T)(img)(x,_p3##y,z,c)), \
   (I[22] = (T)(img)(x,_p2##y,z,c)), \
   (I[31] = (T)(img)(x,_p1##y,z,c)), \
   (I[40] = (T)(img)(x,y,z,c)), \
   (I[49] = (T)(img)(x,_n1##y,z,c)), \
   (I[58] = (T)(img)(x,_n2##y,z,c)), \
   (I[67] = (T)(img)(x,_n3##y,z,c)), \
   (I[76] = (T)(img)(x,_n4##y,z,c)), \
   (I[5] = (T)(img)(_n1##x,_p4##y,z,c)), \
   (I[14] = (T)(img)(_n1##x,_p3##y,z,c)), \
   (I[23] = (T)(img)(_n1##x,_p2##y,z,c)), \
   (I[32] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[41] = (T)(img)(_n1##x,y,z,c)), \
   (I[50] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[59] = (T)(img)(_n1##x,_n2##y,z,c)), \
   (I[68] = (T)(img)(_n1##x,_n3##y,z,c)), \
   (I[77] = (T)(img)(_n1##x,_n4##y,z,c)), \
   (I[6] = (T)(img)(_n2##x,_p4##y,z,c)), \
   (I[15] = (T)(img)(_n2##x,_p3##y,z,c)), \
   (I[24] = (T)(img)(_n2##x,_p2##y,z,c)), \
   (I[33] = (T)(img)(_n2##x,_p1##y,z,c)), \
   (I[42] = (T)(img)(_n2##x,y,z,c)), \
   (I[51] = (T)(img)(_n2##x,_n1##y,z,c)), \
   (I[60] = (T)(img)(_n2##x,_n2##y,z,c)), \
   (I[69] = (T)(img)(_n2##x,_n3##y,z,c)), \
   (I[78] = (T)(img)(_n2##x,_n4##y,z,c)), \
   (I[7] = (T)(img)(_n3##x,_p4##y,z,c)), \
   (I[16] = (T)(img)(_n3##x,_p3##y,z,c)), \
   (I[25] = (T)(img)(_n3##x,_p2##y,z,c)), \
   (I[34] = (T)(img)(_n3##x,_p1##y,z,c)), \
   (I[43] = (T)(img)(_n3##x,y,z,c)), \
   (I[52] = (T)(img)(_n3##x,_n1##y,z,c)), \
   (I[61] = (T)(img)(_n3##x,_n2##y,z,c)), \
   (I[70] = (T)(img)(_n3##x,_n3##y,z,c)), \
   (I[79] = (T)(img)(_n3##x,_n4##y,z,c)), \
   x+4>=(img).width()?(img).width()-1:x+4); \
   x<=(int)(x1) && ((_n4##x<(img).width() && ( \
   (I[8] = (T)(img)(_n4##x,_p4##y,z,c)), \
   (I[17] = (T)(img)(_n4##x,_p3##y,z,c)), \
   (I[26] = (T)(img)(_n4##x,_p2##y,z,c)), \
   (I[35] = (T)(img)(_n4##x,_p1##y,z,c)), \
   (I[44] = (T)(img)(_n4##x,y,z,c)), \
   (I[53] = (T)(img)(_n4##x,_n1##y,z,c)), \
   (I[62] = (T)(img)(_n4##x,_n2##y,z,c)), \
   (I[71] = (T)(img)(_n4##x,_n3##y,z,c)), \
   (I[80] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \
   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \
   I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
   I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], \
   I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
   I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], \
   I[45] = I[46], I[46] = I[47], I[47] = I[48], I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], \
   I[54] = I[55], I[55] = I[56], I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], \
   I[63] = I[64], I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \
   I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], I[79] = I[80], \
   _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)

#define cimg_for2x2x2(img,x,y,z,c,I,T) \
 cimg_for2((img)._depth,z) cimg_for2((img)._height,y) for (int x = 0, \
   _n1##x = (int)( \
   (I[0] = (T)(img)(0,y,z,c)), \
   (I[2] = (T)(img)(0,_n1##y,z,c)), \
   (I[4] = (T)(img)(0,y,_n1##z,c)), \
   (I[6] = (T)(img)(0,_n1##y,_n1##z,c)), \
   1>=(img)._width?(img).width()-1:1); \
   (_n1##x<(img).width() && ( \
   (I[1] = (T)(img)(_n1##x,y,z,c)), \
   (I[3] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[5] = (T)(img)(_n1##x,y,_n1##z,c)), \
   (I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \
   x==--_n1##x; \
   I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
   ++x, ++_n1##x)

#define cimg_for_in2x2x2(img,x0,y0,z0,x1,y1,z1,x,y,z,c,I,T) \
 cimg_for_in2((img)._depth,z0,z1,z) cimg_for_in2((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
   _n1##x = (int)( \
   (I[0] = (T)(img)(x,y,z,c)), \
   (I[2] = (T)(img)(x,_n1##y,z,c)), \
   (I[4] = (T)(img)(x,y,_n1##z,c)), \
   (I[6] = (T)(img)(x,_n1##y,_n1##z,c)), \
   x+1>=(int)(img)._width?(img).width()-1:x+1); \
   x<=(int)(x1) && ((_n1##x<(img).width() && ( \
   (I[1] = (T)(img)(_n1##x,y,z,c)), \
   (I[3] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[5] = (T)(img)(_n1##x,y,_n1##z,c)), \
   (I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \
   x==--_n1##x); \
   I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
   ++x, ++_n1##x)

#define cimg_for3x3x3(img,x,y,z,c,I,T) \
 cimg_for3((img)._depth,z) cimg_for3((img)._height,y) for (int x = 0, \
   _p1##x = 0, \
   _n1##x = (int)( \
   (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,_p1##z,c)), \
   (I[3] = I[4] = (T)(img)(0,y,_p1##z,c)),  \
   (I[6] = I[7] = (T)(img)(0,_n1##y,_p1##z,c)), \
   (I[9] = I[10] = (T)(img)(0,_p1##y,z,c)), \
   (I[12] = I[13] = (T)(img)(0,y,z,c)), \
   (I[15] = I[16] = (T)(img)(0,_n1##y,z,c)), \
   (I[18] = I[19] = (T)(img)(0,_p1##y,_n1##z,c)), \
   (I[21] = I[22] = (T)(img)(0,y,_n1##z,c)), \
   (I[24] = I[25] = (T)(img)(0,_n1##y,_n1##z,c)), \
   1>=(img)._width?(img).width()-1:1); \
   (_n1##x<(img).width() && ( \
   (I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c)), \
   (I[5] = (T)(img)(_n1##x,y,_p1##z,c)), \
   (I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c)), \
   (I[11] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[14] = (T)(img)(_n1##x,y,z,c)), \
   (I[17] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c)), \
   (I[23] = (T)(img)(_n1##x,y,_n1##z,c)), \
   (I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \
   x==--_n1##x; \
   I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
   I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
   I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
   _p1##x = x++, ++_n1##x)

#define cimg_for_in3x3x3(img,x0,y0,z0,x1,y1,z1,x,y,z,c,I,T) \
 cimg_for_in3((img)._depth,z0,z1,z) cimg_for_in3((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
   _p1##x = x-1<0?0:x-1, \
   _n1##x = (int)( \
   (I[0] = (T)(img)(_p1##x,_p1##y,_p1##z,c)), \
   (I[3] = (T)(img)(_p1##x,y,_p1##z,c)),  \
   (I[6] = (T)(img)(_p1##x,_n1##y,_p1##z,c)), \
   (I[9] = (T)(img)(_p1##x,_p1##y,z,c)), \
   (I[12] = (T)(img)(_p1##x,y,z,c)), \
   (I[15] = (T)(img)(_p1##x,_n1##y,z,c)), \
   (I[18] = (T)(img)(_p1##x,_p1##y,_n1##z,c)), \
   (I[21] = (T)(img)(_p1##x,y,_n1##z,c)), \
   (I[24] = (T)(img)(_p1##x,_n1##y,_n1##z,c)), \
   (I[1] = (T)(img)(x,_p1##y,_p1##z,c)), \
   (I[4] = (T)(img)(x,y,_p1##z,c)),  \
   (I[7] = (T)(img)(x,_n1##y,_p1##z,c)), \
   (I[10] = (T)(img)(x,_p1##y,z,c)), \
   (I[13] = (T)(img)(x,y,z,c)), \
   (I[16] = (T)(img)(x,_n1##y,z,c)), \
   (I[19] = (T)(img)(x,_p1##y,_n1##z,c)), \
   (I[22] = (T)(img)(x,y,_n1##z,c)), \
   (I[25] = (T)(img)(x,_n1##y,_n1##z,c)), \
   x+1>=(int)(img)._width?(img).width()-1:x+1); \
   x<=(int)(x1) && ((_n1##x<(img).width() && ( \
   (I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c)), \
   (I[5] = (T)(img)(_n1##x,y,_p1##z,c)), \
   (I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c)), \
   (I[11] = (T)(img)(_n1##x,_p1##y,z,c)), \
   (I[14] = (T)(img)(_n1##x,y,z,c)), \
   (I[17] = (T)(img)(_n1##x,_n1##y,z,c)), \
   (I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c)), \
   (I[23] = (T)(img)(_n1##x,y,_n1##z,c)), \
   (I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \
   x==--_n1##x); \
   I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
   I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
   I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
   _p1##x = x++, ++_n1##x)

#define cimglist_for(list,l) for (int l = 0; l<(int)(list)._width; ++l)
#define cimglist_for_in(list,l0,l1,l) \
  for (int l = (int)(l0)<0?0:(int)(l0), _max##l = (unsigned int)l1<(list)._width?(int)(l1):(int)(list)._width-1; l<=_max##l; ++l)

#define cimglist_apply(list,fn) cimglist_for(list,__##fn) (list)[__##fn].fn

// Define macros used when exceptions are thrown.
#define _cimgdisplay_instance "[instance(%u,%u,%u,%c%s%c)] CImgDisplay::"
#define cimgdisplay_instance _width,_height,_normalization,_title?'\"':'[',_title?_title:"untitled",_title?'\"':']'
#define _cimg_instance "[instance(%u,%u,%u,%u,%p,%sshared)] CImg<%s>::"
#define cimg_instance _width,_height,_depth,_spectrum,_data,_is_shared?"":"non-",pixel_type()
#define _cimglist_instance "[instance(%u,%u,%p)] CImgList<%s>::"
#define cimglist_instance _width,_allocated_width,_data,pixel_type()

/*------------------------------------------------
 #
 #
 #  Definition of the cimg_library:: namespace
 #
 #
 -------------------------------------------------*/
//! This namespace encompasses all classes and functions of the %CImg library.
/**
   This namespace is defined to avoid functions and class names collisions
   that could happen with the include of other C++ header files.
   Anyway, it should not happen often and you should reasonnably start most of your
   %CImg-based programs with
   \code
   #include "CImg.h"
   using namespace cimg_library;
   \endcode
   to simplify the declaration of %CImg Library variables afterwards.
**/
namespace cimg_library {

  // Declare the only four classes of the CImg Library.
  template<typename T=float> struct CImg;
  template<typename T=float> struct CImgList;
  struct CImgDisplay;
  struct CImgException;

  // (Pre)declare the cimg namespace.
  // This is not the complete namespace declaration. It only contains some
  // necessary stuffs to ensure a correct declaration order of classes and functions
  // defined afterwards.
  namespace cimg {

#ifdef cimg_use_vt100
    const char t_normal[] = { 0x1b, '[', '0', ';', '0', ';', '0', 'm', 0 };
    const char t_red[] = { 0x1b, '[', '4', ';', '3', '1', ';', '5', '9', 'm', 0 };
    const char t_bold[] = { 0x1b, '[', '1', 'm', 0 };
    const char t_purple[] = { 0x1b, '[', '0', ';', '3', '5', ';', '5', '9', 'm', 0 };
    const char t_green[] = { 0x1b, '[', '0', ';', '3', '2', ';', '5', '9', 'm', 0 };
#else
    const char t_normal[] = { 0 };
    const char *const t_red = cimg::t_normal, *const t_bold = cimg::t_normal,
      *const t_purple = cimg::t_normal, *const t_green = cimg::t_normal;
#endif

    inline std::FILE* output(std::FILE *file=0);
    inline void info();

    // Function used to avoid warning messages due to unused parameters.
    template<typename T>
    inline void unused(const T&, ...) {}

    //! Get/set the current CImg exception mode.
    /**
       The way error messages are handled by CImg can be changed dynamically, using this function.
       Possible values are :
       - '0' to hide library messages (quiet mode).
       - '1' to print library messages on the console.
       - '2' to display library messages on a dialog window (default behavior).
       - '3' to do as '1' + add extra warnings (may slow down the code !).
       - '4' to do as '2' + add extra warnings (may slow down the code !).
     **/
    inline unsigned int& _exception_mode(const unsigned int value, const bool is_set) {
      static unsigned int mode = cimg_verbosity;
      if (is_set) mode = value;
      return mode;
    }
    inline unsigned int& exception_mode() {
      return _exception_mode(0,false);
    }
    inline unsigned int& exception_mode(const unsigned int mode) {
      return _exception_mode(mode,true);
    }

    inline int dialog(const char *const title, const char *const msg, const char *const button1_label="OK",
                      const char *const button2_label=0, const char *const button3_label=0,
                      const char *const button4_label=0, const char *const button5_label=0,
                      const char *const button6_label=0, const bool centering=false);

    //! Evaluate math expression.
    inline double eval(const char *const expression, const double x=0, const double y=0, const double z=0, const double v=0);
  }

  /*----------------------------------------------
   #
   # Definition of the CImgException structures
   #
   ----------------------------------------------*/
  //! Instances of this class are thrown when errors occur during a %CImg library function call.
  /**
     \section ex1 Overview

      CImgException is the base class of %CImg exceptions.
      Exceptions are thrown by the %CImg Library when an error occured in a %CImg library function call.
      CImgException is seldom thrown itself. Children classes that specify the kind of error encountered
      are generally used instead. These sub-classes are :

      - \b CImgInstanceException : Thrown when the instance associated to the called %CImg function is not
      correctly defined. Generally, this exception is thrown when one tries to process \a empty images. The example
      below will throw a \a CImgInstanceException.
      \code
      CImg<float> img;        // Construct an empty image.
      img.blur(10);           // Try to blur the image.
      \endcode

      - \b CImgArgumentException : Thrown when one of the arguments given to the called %CImg function is not correct.
      Generally, this exception is thrown when arguments passed to the function are outside an admissible range of values.
      The example below will throw a \a CImgArgumentException.
      \code
      CImg<float> img(100,100,1,3);   // Define a 100x100 color image with float pixels.
      img = 0;                     // Try to fill pixels from the 0 pointer (invalid argument to operator=() ).
      \endcode

      - \b CImgIOException : Thrown when an error occured when trying to load or save image files.
      The example below will throw a \a CImgIOException.
      \code
      CImg<float> img("file_doesnt_exist.jpg");    // Try to load a file that doesn't exist.
      \endcode

      The parent class CImgException may be thrown itself when errors that cannot be classified in one of
      the above type occur. It is recommended not to throw CImgExceptions yourself, since there are normally
      reserved to %CImg Library functions.
      \b CImgInstanceException, \b CImgArgumentException and \b CImgIOException are simple
      subclasses of CImgException and are thus not detailled more in this reference documentation.

      \section ex2 Exception handling

      When an error occurs, the %CImg Library first displays the error in a modal window.
      Then, it throws an instance of the corresponding exception class, generally leading the program to stop
      (this is the default behavior).
      You can bypass this default behavior by handling the exceptions yourself,
      using a code block <tt>try { ... } catch () { ... }</tt>.
      In this case, you can avoid the apparition of the modal window, by
      defining the environment variable <tt>cimg_verbosity</tt> to 0 before including the %CImg header file.
      The example below shows how to cleanly handle %CImg Library exceptions :
      \code
      #define cimg_verbosity 0     // Disable modal window in CImg exceptions.
      #define "CImg.h"
      int main() {
        try {
          ...; // Here, do what you want.
        }
        catch (CImgInstanceException &e) {
          std::fprintf(stderr,"CImg Library Error : %s",e.what());  // Display your own error message
          ...                                                       // Do what you want now.
        }
      }
      \endcode
  **/
  struct CImgException : public std::exception {
#define _cimg_exception_err(etype,disp_flag) \
  std::va_list ap; va_start(ap,format); cimg_vsnprintf(_message,sizeof(_message),format,ap); va_end(ap); \
  if (cimg::exception_mode()) { \
    std::fprintf(cimg::output(),"\n%s[CImg] *** %s ***%s %s\n",cimg::t_red,etype,cimg::t_normal,_message); \
    if (cimg_display && disp_flag && !(cimg::exception_mode()%2)) try { cimg::dialog(etype,_message,"Abort"); } catch (CImgException&) {} \
    if (cimg::exception_mode()>=3) cimg_library::cimg::info(); \
  }

    char _message[16384];
    CImgException() { *_message = 0; }
    CImgException(const char *const format, ...) { _cimg_exception_err("CImgException",true); }
    const char *what() const throw() { return _message; }
  };

  // The CImgInstanceException class is used to throw an exception related
  // to a non suitable instance encountered in a library function call.
  struct CImgInstanceException : public CImgException {
    CImgInstanceException(const char *const format, ...) { _cimg_exception_err("CImgInstanceException",true); }
  };

  // The CImgArgumentException class is used to throw an exception related
  // to invalid arguments encountered in a library function call.
  struct CImgArgumentException : public CImgException {
    CImgArgumentException(const char *const format, ...) { _cimg_exception_err("CImgArgumentException",true); }
  };

  // The CImgIOException class is used to throw an exception related
  // to Input/Output file problems encountered in a library function call.
  struct CImgIOException : public CImgException {
    CImgIOException(const char *const format, ...) { _cimg_exception_err("CImgIOException",true); }
  };

  // The CImgDisplayException class is used to throw an exception related
  // to display problems encountered in a library function call.
  struct CImgDisplayException : public CImgException {
    CImgDisplayException(const char *const format, ...) { _cimg_exception_err("CImgDisplayException",false); }
  };

  // The CImgWarningException class is used to throw an exception for warnings
  // encountered in a library function call.
  struct CImgWarningException : public CImgException {
    CImgWarningException(const char *const format, ...) { _cimg_exception_err("CImgWarningException",false); }
  };

  /*-------------------------------------
   #
   # Definition of the namespace 'cimg'
   #
   --------------------------------------*/
  //! Namespace that encompasses \a low-level functions and variables of the %CImg Library.
  /**
     Most of the functions and variables within this namespace are used by the library for low-level processing.
     Nevertheless, documented variables and functions of this namespace may be used safely in your own source code.

     \warning Never write <tt>using namespace cimg_library::cimg;</tt> in your source code, since a lot of functions of the
     <tt>cimg::</tt> namespace have prototypes similar to standard C functions that could defined in the global namespace <tt>::</tt>.
  **/
  namespace cimg {

    // Define the traits that will be used to determine the best data type to work with.
    //
    template<typename T> struct type {
      static const char* string() {
        static const char* s[] = { "unknown",   "unknown8",   "unknown16",  "unknown24",
                                   "unknown32", "unknown40",  "unknown48",  "unknown56",
                                   "unknown64", "unknown72",  "unknown80",  "unknown88",
                                   "unknown96", "unknown104", "unknown112", "unknown120",
                                   "unknown128" };
        return s[(sizeof(T)<17)?sizeof(T):0];
      }
      static unsigned int id() { return 0U; }
      static bool is_float() { return false; }
      static T min() { return (T)-1>0?(T)0:(T)-1<<(8*sizeof(T)-1); }
      static T max() { return (T)-1>0?(T)-1:~((T)-1<<(8*sizeof(T)-1)); }
      static T cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(T)val; }
      static const char* format() { return "%s"; }
      static const char* format(const T val) { static const char *const s = "unknown"; return s; }
    };

    template<> struct type<bool> {
      static const char* string() { static const char *const s = "bool"; return s; }
      static unsigned int id() { return 1U; }
      static bool is_float() { return false; }
      static bool min() { return false; }
      static bool max() { return true; }
      static bool cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(bool)val; }
      static const char* format() { return "%s"; }
      static const char* format(const bool val) { static const char* s[] = { "false", "true" }; return s[val?1:0]; }
    };

    template<> struct type<unsigned char> {
      static const char* string() { static const char *const s = "unsigned char"; return s; }
      static unsigned int id() { return 2U; }
      static bool is_float() { return false; }
      static unsigned char min() { return 0; }
      static unsigned char max() { return (unsigned char)~0U; }
      static unsigned char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned char)val; }
      static const char* format() { return "%u"; }
      static unsigned int format(const unsigned char val) { return (unsigned int)val; }
    };

    template<> struct type<char> {
      static const char* string() { static const char *const s = "char"; return s; }
      static unsigned int id() { return 3U; }
      static bool is_float() { return false; }
      static char min() { return (char)(-1L<<(8*sizeof(char)-1)); }
      static char max() { return ~((char)(-1L<<(8*sizeof(char)-1))); }
      static char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(char)val; }
      static const char* format() { return "%d"; }
      static int format(const char val) { return (int)val; }
    };

    template<> struct type<signed char> {
      static const char* string() { static const char *const s = "signed char"; return s; }
      static unsigned int id() { return 4U; }
      static bool is_float() { return false; }
      static signed char min() { return (signed char)(-1L<<(8*sizeof(signed char)-1)); }
      static signed char max() { return ~((signed char)(-1L<<(8*sizeof(signed char)-1))); }
      static signed char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(signed char)val; }
      static const char* format() { return "%d"; }
      static unsigned int format(const signed char val) { return (int)val; }
    };

    template<> struct type<unsigned short> {
      static const char* string() { static const char *const s = "unsigned short"; return s; }
      static unsigned int id() { return 5U; }
      static bool is_float() { return false; }
      static unsigned short min() { return 0; }
      static unsigned short max() { return (unsigned short)~0U; }
      static unsigned short cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned short)val; }
      static const char* format() { return "%u"; }
      static unsigned int format(const unsigned short val) { return (unsigned int)val; }
    };

    template<> struct type<short> {
      static const char* string() { static const char *const s = "short"; return s; }
      static unsigned int id() { return 6U; }
      static bool is_float() { return false; }
      static short min() { return (short)(-1L<<(8*sizeof(short)-1)); }
      static short max() { return ~((short)(-1L<<(8*sizeof(short)-1))); }
      static short cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(short)val; }
      static const char* format() { return "%d"; }
      static int format(const short val) { return (int)val; }
    };

    template<> struct type<unsigned int> {
      static const char* string() { static const char *const s = "unsigned int"; return s; }
      static unsigned int id() { return 7U; }
      static bool is_float() { return false; }
      static unsigned int min() { return 0; }
      static unsigned int max() { return (unsigned int)~0U; }
      static unsigned int cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned int)val; }
      static const char* format() { return "%u"; }
      static unsigned int format(const unsigned int val) { return val; }
    };

    template<> struct type<int> {
      static const char* string() { static const char *const s = "int"; return s; }
      static unsigned int id() { return 8U; }
      static bool is_float() { return false; }
      static int min() { return (int)(-1L<<(8*sizeof(int)-1)); }
      static int max() { return ~((int)(-1L<<(8*sizeof(int)-1))); }
      static int cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(int)val; }
      static const char* format() { return "%d"; }
      static int format(const int val) { return val; }
    };

    template<> struct type<unsigned long> {
      static const char* string() { static const char *const s = "unsigned long"; return s; }
      static unsigned int id() { return 9U; }
      static bool is_float() { return false; }
      static unsigned long min() { return 0; }
      static unsigned long max() { return (unsigned long)~0UL; }
      static unsigned long cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(unsigned long)val; }
      static const char* format() { return "%lu"; }
      static unsigned long format(const unsigned long val) { return val; }
    };

    template<> struct type<long> {
      static const char* string() { static const char *const s = "long"; return s; }
      static unsigned int id() { return 10U; }
      static bool is_float() { return false; }
      static long min() { return (long)(-1L<<(8*sizeof(long)-1)); }
      static long max() { return ~((long)(-1L<<(8*sizeof(long)-1))); }
      static long cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(long)val; }
      static const char* format() { return "%ld"; }
      static long format(const long val) { return val; }
    };

    template<> struct type<double> {
      static const char* string() { static const char *const s = "double"; return s; }
      static unsigned int id() { return 11U; }
      static bool is_float() { return true; }
      static double min() { return -1.7E308; }
      static double max() { return  1.7E308; }
      static double cut(const double val) { return val<min()?min():val>max()?max():val; }
      static double inf() { return max()*max(); }
      static double nan() { static const double v_nan = std::sqrt(-1.0); return v_nan; }
      static const char* format() { return "%g"; }
      static double format(const double val) { return val; }
    };

    template<> struct type<float> {
      static const char* string() { static const char *const s = "float"; return s; }
      static unsigned int id() { return 12U; }
      static bool is_float() { return true; }
      static float min() { return -3.4E38f; }
      static float max() { return  3.4E38f; }
      static float cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(float)val; }
      static float inf() { return (float)cimg::type<double>::inf(); }
      static float nan() { return (float)cimg::type<double>::nan(); }
      static const char* format() { return "%g"; }
      static double format(const float val) { return (double)val; }
    };

    template<typename T, typename t> struct superset { typedef T type; };
    template<> struct superset<bool,unsigned char> { typedef unsigned char type; };
    template<> struct superset<bool,char> { typedef char type; };
    template<> struct superset<bool,signed char> { typedef signed char type; };
    template<> struct superset<bool,unsigned short> { typedef unsigned short type; };
    template<> struct superset<bool,short> { typedef short type; };
    template<> struct superset<bool,unsigned int> { typedef unsigned int type; };
    template<> struct superset<bool,int> { typedef int type; };
    template<> struct superset<bool,unsigned long> { typedef unsigned long type; };
    template<> struct superset<bool,long> { typedef long type; };
    template<> struct superset<bool,float> { typedef float type; };
    template<> struct superset<bool,double> { typedef double type; };
    template<> struct superset<unsigned char,char> { typedef short type; };
    template<> struct superset<unsigned char,signed char> { typedef short type; };
    template<> struct superset<unsigned char,unsigned short> { typedef unsigned short type; };
    template<> struct superset<unsigned char,short> { typedef short type; };
    template<> struct superset<unsigned char,unsigned int> { typedef unsigned int type; };
    template<> struct superset<unsigned char,int> { typedef int type; };
    template<> struct superset<unsigned char,unsigned long> { typedef unsigned long type; };
    template<> struct superset<unsigned char,long> { typedef long type; };
    template<> struct superset<unsigned char,float> { typedef float type; };
    template<> struct superset<unsigned char,double> { typedef double type; };
    template<> struct superset<signed char,unsigned char> { typedef short type; };
    template<> struct superset<signed char,char> { typedef short type; };
    template<> struct superset<signed char,unsigned short> { typedef int type; };
    template<> struct superset<signed char,short> { typedef short type; };
    template<> struct superset<signed char,unsigned int> { typedef long type; };
    template<> struct superset<signed char,int> { typedef int type; };
    template<> struct superset<signed char,unsigned long> { typedef long type; };
    template<> struct superset<signed char,long> { typedef long type; };
    template<> struct superset<signed char,float> { typedef float type; };
    template<> struct superset<signed char,double> { typedef double type; };
    template<> struct superset<char,unsigned char> { typedef short type; };
    template<> struct superset<char,signed char> { typedef short type; };
    template<> struct superset<char,unsigned short> { typedef int type; };
    template<> struct superset<char,short> { typedef short type; };
    template<> struct superset<char,unsigned int> { typedef long type; };
    template<> struct superset<char,int> { typedef int type; };
    template<> struct superset<char,unsigned long> { typedef long type; };
    template<> struct superset<char,long> { typedef long type; };
    template<> struct superset<char,float> { typedef float type; };
    template<> struct superset<char,double> { typedef double type; };
    template<> struct superset<unsigned short,char> { typedef int type; };
    template<> struct superset<unsigned short,signed char> { typedef int type; };
    template<> struct superset<unsigned short,short> { typedef int type; };
    template<> struct superset<unsigned short,unsigned int> { typedef unsigned int type; };
    template<> struct superset<unsigned short,int> { typedef int type; };
    template<> struct superset<unsigned short,unsigned long> { typedef unsigned long type; };
    template<> struct superset<unsigned short,long> { typedef long type; };
    template<> struct superset<unsigned short,float> { typedef float type; };
    template<> struct superset<unsigned short,double> { typedef double type; };
    template<> struct superset<short,unsigned short> { typedef int type; };
    template<> struct superset<short,unsigned int> { typedef long type; };
    template<> struct superset<short,int> { typedef int type; };
    template<> struct superset<short,unsigned long> { typedef long type; };
    template<> struct superset<short,long> { typedef long type; };
    template<> struct superset<short,float> { typedef float type; };
    template<> struct superset<short,double> { typedef double type; };
    template<> struct superset<unsigned int,char> { typedef long type; };
    template<> struct superset<unsigned int,signed char> { typedef long type; };
    template<> struct superset<unsigned int,short> { typedef long type; };
    template<> struct superset<unsigned int,int> { typedef long type; };
    template<> struct superset<unsigned int,unsigned long> { typedef unsigned long type; };
    template<> struct superset<unsigned int,long> { typedef long type; };
    template<> struct superset<unsigned int,float> { typedef float type; };
    template<> struct superset<unsigned int,double> { typedef double type; };
    template<> struct superset<int,unsigned int> { typedef long type; };
    template<> struct superset<int,unsigned long> { typedef long type; };
    template<> struct superset<int,long> { typedef long type; };
    template<> struct superset<int,float> { typedef float type; };
    template<> struct superset<int,double> { typedef double type; };
    template<> struct superset<unsigned long,char> { typedef long type; };
    template<> struct superset<unsigned long,signed char> { typedef long type; };
    template<> struct superset<unsigned long,short> { typedef long type; };
    template<> struct superset<unsigned long,int> { typedef long type; };
    template<> struct superset<unsigned long,long> { typedef long type; };
    template<> struct superset<unsigned long,float> { typedef float type; };
    template<> struct superset<unsigned long,double> { typedef double type; };
    template<> struct superset<long,float> { typedef float type; };
    template<> struct superset<long,double> { typedef double type; };
    template<> struct superset<float,double> { typedef double type; };

    template<typename t1, typename t2, typename t3> struct superset2 {
      typedef typename superset<t1, typename superset<t2,t3>::type>::type type;
    };

    template<typename t1, typename t2, typename t3, typename t4> struct superset3 {
      typedef typename superset<t1, typename superset2<t2,t3,t4>::type>::type type;
    };

    template<typename t1, typename t2> struct last { typedef t2 type; };

#define _cimg_Tt      typename cimg::superset<T,t>::type
#define _cimg_Tfloat  typename cimg::superset<T,float>::type
#define _cimg_Ttfloat typename cimg::superset2<T,t,float>::type

    // Define internal library variables.
#if cimg_display==1
    struct X11_info {
      volatile unsigned int nb_wins;
      pthread_t*       event_thread;
      CImgDisplay*     wins[1024];
      Display*         display;
      unsigned int     nb_bits;
      bool             is_blue_first;
      bool             is_shm_enabled;
      bool             byte_order;
#ifdef cimg_use_xrandr
      XRRScreenSize *resolutions;
      Rotation curr_rotation;
      unsigned int curr_resolution;
      unsigned int nb_resolutions;
#endif
      X11_info():nb_wins(0),event_thread(0),display(0),
                 nb_bits(0),is_blue_first(false),is_shm_enabled(false),byte_order(false) {
#ifdef cimg_use_xrandr
        resolutions = 0;
        curr_rotation = 0;
        curr_resolution = nb_resolutions = 0;
#endif
      }
    };
#if defined(cimg_module)
    X11_info& X11_attr();
#elif defined(cimg_main)
    X11_info& X11_attr() { static X11_info val; return val; }
#else
    inline X11_info& X11_attr() { static X11_info val; return val; }
#endif

#elif cimg_display==2
    struct Win32_info {
      HANDLE wait_event;
      Win32_info() { wait_event = CreateEvent(0,FALSE,FALSE,0); }
    };
#if defined(cimg_module)
    Win32_info& Win32_attr();
#elif defined(cimg_main)
    Win32_info& Win32_attr() { static Win32_info val; return val; }
#else
    inline Win32_info& Win32_attr() { static Win32_info val; return val; }
#endif
#endif

#if defined(cimg_use_magick)
    static struct Magick_info {
      Magick_info() {
        Magick::InitializeMagick("");
      }
    } _Magick_info;
#endif

#if cimg_display==1
    // Keycodes for X11-based graphical systems.
    const unsigned int keyESC        = XK_Escape;
    const unsigned int keyF1         = XK_F1;
    const unsigned int keyF2         = XK_F2;
    const unsigned int keyF3         = XK_F3;
    const unsigned int keyF4         = XK_F4;
    const unsigned int keyF5         = XK_F5;
    const unsigned int keyF6         = XK_F6;
    const unsigned int keyF7         = XK_F7;
    const unsigned int keyF8         = XK_F8;
    const unsigned int keyF9         = XK_F9;
    const unsigned int keyF10        = XK_F10;
    const unsigned int keyF11        = XK_F11;
    const unsigned int keyF12        = XK_F12;
    const unsigned int keyPAUSE      = XK_Pause;
    const unsigned int key1          = XK_1;
    const unsigned int key2          = XK_2;
    const unsigned int key3          = XK_3;
    const unsigned int key4          = XK_4;
    const unsigned int key5          = XK_5;
    const unsigned int key6          = XK_6;
    const unsigned int key7          = XK_7;
    const unsigned int key8          = XK_8;
    const unsigned int key9          = XK_9;
    const unsigned int key0          = XK_0;
    const unsigned int keyBACKSPACE  = XK_BackSpace;
    const unsigned int keyINSERT     = XK_Insert;
    const unsigned int keyHOME       = XK_Home;
    const unsigned int keyPAGEUP     = XK_Page_Up;
    const unsigned int keyTAB        = XK_Tab;
    const unsigned int keyQ          = XK_q;
    const unsigned int keyW          = XK_w;
    const unsigned int keyE          = XK_e;
    const unsigned int keyR          = XK_r;
    const unsigned int keyT          = XK_t;
    const unsigned int keyY          = XK_y;
    const unsigned int keyU          = XK_u;
    const unsigned int keyI          = XK_i;
    const unsigned int keyO          = XK_o;
    const unsigned int keyP          = XK_p;
    const unsigned int keyDELETE     = XK_Delete;
    const unsigned int keyEND        = XK_End;
    const unsigned int keyPAGEDOWN   = XK_Page_Down;
    const unsigned int keyCAPSLOCK   = XK_Caps_Lock;
    const unsigned int keyA          = XK_a;
    const unsigned int keyS          = XK_s;
    const unsigned int keyD          = XK_d;
    const unsigned int keyF          = XK_f;
    const unsigned int keyG          = XK_g;
    const unsigned int keyH          = XK_h;
    const unsigned int keyJ          = XK_j;
    const unsigned int keyK          = XK_k;
    const unsigned int keyL          = XK_l;
    const unsigned int keyENTER      = XK_Return;
    const unsigned int keySHIFTLEFT  = XK_Shift_L;
    const unsigned int keyZ          = XK_z;
    const unsigned int keyX          = XK_x;
    const unsigned int keyC          = XK_c;
    const unsigned int keyV          = XK_v;
    const unsigned int keyB          = XK_b;
    const unsigned int keyN          = XK_n;
    const unsigned int keyM          = XK_m;
    const unsigned int keySHIFTRIGHT = XK_Shift_R;
    const unsigned int keyARROWUP    = XK_Up;
    const unsigned int keyCTRLLEFT   = XK_Control_L;
    const unsigned int keyAPPLEFT    = XK_Super_L;
    const unsigned int keyALT        = XK_Alt_L;
    const unsigned int keySPACE      = XK_space;
    const unsigned int keyALTGR      = XK_Alt_R;
    const unsigned int keyAPPRIGHT   = XK_Super_R;
    const unsigned int keyMENU       = XK_Menu;
    const unsigned int keyCTRLRIGHT  = XK_Control_R;
    const unsigned int keyARROWLEFT  = XK_Left;
    const unsigned int keyARROWDOWN  = XK_Down;
    const unsigned int keyARROWRIGHT = XK_Right;
    const unsigned int keyPAD0       = XK_KP_0;
    const unsigned int keyPAD1       = XK_KP_1;
    const unsigned int keyPAD2       = XK_KP_2;
    const unsigned int keyPAD3       = XK_KP_3;
    const unsigned int keyPAD4       = XK_KP_4;
    const unsigned int keyPAD5       = XK_KP_5;
    const unsigned int keyPAD6       = XK_KP_6;
    const unsigned int keyPAD7       = XK_KP_7;
    const unsigned int keyPAD8       = XK_KP_8;
    const unsigned int keyPAD9       = XK_KP_9;
    const unsigned int keyPADADD     = XK_KP_Add;
    const unsigned int keyPADSUB     = XK_KP_Subtract;
    const unsigned int keyPADMUL     = XK_KP_Multiply;
    const unsigned int keyPADDIV     = XK_KP_Divide;

#elif cimg_display==2
    // Keycodes for Windows.
    const unsigned int keyESC        = VK_ESCAPE;
    const unsigned int keyF1         = VK_F1;
    const unsigned int keyF2         = VK_F2;
    const unsigned int keyF3         = VK_F3;
    const unsigned int keyF4         = VK_F4;
    const unsigned int keyF5         = VK_F5;
    const unsigned int keyF6         = VK_F6;
    const unsigned int keyF7         = VK_F7;
    const unsigned int keyF8         = VK_F8;
    const unsigned int keyF9         = VK_F9;
    const unsigned int keyF10        = VK_F10;
    const unsigned int keyF11        = VK_F11;
    const unsigned int keyF12        = VK_F12;
    const unsigned int keyPAUSE      = VK_PAUSE;
    const unsigned int key1          = '1';
    const unsigned int key2          = '2';
    const unsigned int key3          = '3';
    const unsigned int key4          = '4';
    const unsigned int key5          = '5';
    const unsigned int key6          = '6';
    const unsigned int key7          = '7';
    const unsigned int key8          = '8';
    const unsigned int key9          = '9';
    const unsigned int key0          = '0';
    const unsigned int keyBACKSPACE  = VK_BACK;
    const unsigned int keyINSERT     = VK_INSERT;
    const unsigned int keyHOME       = VK_HOME;
    const unsigned int keyPAGEUP     = VK_PRIOR;
    const unsigned int keyTAB        = VK_TAB;
    const unsigned int keyQ          = 'Q';
    const unsigned int keyW          = 'W';
    const unsigned int keyE          = 'E';
    const unsigned int keyR          = 'R';
    const unsigned int keyT          = 'T';
    const unsigned int keyY          = 'Y';
    const unsigned int keyU          = 'U';
    const unsigned int keyI          = 'I';
    const unsigned int keyO          = 'O';
    const unsigned int keyP          = 'P';
    const unsigned int keyDELETE     = VK_DELETE;
    const unsigned int keyEND        = VK_END;
    const unsigned int keyPAGEDOWN   = VK_NEXT;
    const unsigned int keyCAPSLOCK   = VK_CAPITAL;
    const unsigned int keyA          = 'A';
    const unsigned int keyS          = 'S';
    const unsigned int keyD          = 'D';
    const unsigned int keyF          = 'F';
    const unsigned int keyG          = 'G';
    const unsigned int keyH          = 'H';
    const unsigned int keyJ          = 'J';
    const unsigned int keyK          = 'K';
    const unsigned int keyL          = 'L';
    const unsigned int keyENTER      = VK_RETURN;
    const unsigned int keySHIFTLEFT  = VK_SHIFT;
    const unsigned int keyZ          = 'Z';
    const unsigned int keyX          = 'X';
    const unsigned int keyC          = 'C';
    const unsigned int keyV          = 'V';
    const unsigned int keyB          = 'B';
    const unsigned int keyN          = 'N';
    const unsigned int keyM          = 'M';
    const unsigned int keySHIFTRIGHT = VK_SHIFT;
    const unsigned int keyARROWUP    = VK_UP;
    const unsigned int keyCTRLLEFT   = VK_CONTROL;
    const unsigned int keyAPPLEFT    = VK_LWIN;
    const unsigned int keyALT        = VK_LMENU;
    const unsigned int keySPACE      = VK_SPACE;
    const unsigned int keyALTGR      = VK_CONTROL;
    const unsigned int keyAPPRIGHT   = VK_RWIN;
    const unsigned int keyMENU       = VK_APPS;
    const unsigned int keyCTRLRIGHT  = VK_CONTROL;
    const unsigned int keyARROWLEFT  = VK_LEFT;
    const unsigned int keyARROWDOWN  = VK_DOWN;
    const unsigned int keyARROWRIGHT = VK_RIGHT;
    const unsigned int keyPAD0       = 0x60;
    const unsigned int keyPAD1       = 0x61;
    const unsigned int keyPAD2       = 0x62;
    const unsigned int keyPAD3       = 0x63;
    const unsigned int keyPAD4       = 0x64;
    const unsigned int keyPAD5       = 0x65;
    const unsigned int keyPAD6       = 0x66;
    const unsigned int keyPAD7       = 0x67;
    const unsigned int keyPAD8       = 0x68;
    const unsigned int keyPAD9       = 0x69;
    const unsigned int keyPADADD     = VK_ADD;
    const unsigned int keyPADSUB     = VK_SUBTRACT;
    const unsigned int keyPADMUL     = VK_MULTIPLY;
    const unsigned int keyPADDIV     = VK_DIVIDE;

#else
    // Define unknow keycodes when no display are available.
    // (should rarely be used then !).
    const unsigned int keyESC        = 1U;
    const unsigned int keyF1         = 2U;
    const unsigned int keyF2         = 3U;
    const unsigned int keyF3         = 4U;
    const unsigned int keyF4         = 5U;
    const unsigned int keyF5         = 6U;
    const unsigned int keyF6         = 7U;
    const unsigned int keyF7         = 8U;
    const unsigned int keyF8         = 9U;
    const unsigned int keyF9         = 10U;
    const unsigned int keyF10        = 11U;
    const unsigned int keyF11        = 12U;
    const unsigned int keyF12        = 13U;
    const unsigned int keyPAUSE      = 14U;
    const unsigned int key1          = 15U;
    const unsigned int key2          = 16U;
    const unsigned int key3          = 17U;
    const unsigned int key4          = 18U;
    const unsigned int key5          = 19U;
    const unsigned int key6          = 20U;
    const unsigned int key7          = 21U;
    const unsigned int key8          = 22U;
    const unsigned int key9          = 23U;
    const unsigned int key0          = 24U;
    const unsigned int keyBACKSPACE  = 25U;
    const unsigned int keyINSERT     = 26U;
    const unsigned int keyHOME       = 27U;
    const unsigned int keyPAGEUP     = 28U;
    const unsigned int keyTAB        = 29U;
    const unsigned int keyQ          = 30U;
    const unsigned int keyW          = 31U;
    const unsigned int keyE          = 32U;
    const unsigned int keyR          = 33U;
    const unsigned int keyT          = 34U;
    const unsigned int keyY          = 35U;
    const unsigned int keyU          = 36U;
    const unsigned int keyI          = 37U;
    const unsigned int keyO          = 38U;
    const unsigned int keyP          = 39U;
    const unsigned int keyDELETE     = 40U;
    const unsigned int keyEND        = 41U;
    const unsigned int keyPAGEDOWN   = 42U;
    const unsigned int keyCAPSLOCK   = 43U;
    const unsigned int keyA          = 44U;
    const unsigned int keyS          = 45U;
    const unsigned int keyD          = 46U;
    const unsigned int keyF          = 47U;
    const unsigned int keyG          = 48U;
    const unsigned int keyH          = 49U;
    const unsigned int keyJ          = 50U;
    const unsigned int keyK          = 51U;
    const unsigned int keyL          = 52U;
    const unsigned int keyENTER      = 53U;
    const unsigned int keySHIFTLEFT  = 54U;
    const unsigned int keyZ          = 55U;
    const unsigned int keyX          = 56U;
    const unsigned int keyC          = 57U;
    const unsigned int keyV          = 58U;
    const unsigned int keyB          = 59U;
    const unsigned int keyN          = 60U;
    const unsigned int keyM          = 61U;
    const unsigned int keySHIFTRIGHT = 62U;
    const unsigned int keyARROWUP    = 63U;
    const unsigned int keyCTRLLEFT   = 64U;
    const unsigned int keyAPPLEFT    = 65U;
    const unsigned int keyALT        = 66U;
    const unsigned int keySPACE      = 67U;
    const unsigned int keyALTGR      = 68U;
    const unsigned int keyAPPRIGHT   = 69U;
    const unsigned int keyMENU       = 70U;
    const unsigned int keyCTRLRIGHT  = 71U;
    const unsigned int keyARROWLEFT  = 72U;
    const unsigned int keyARROWDOWN  = 73U;
    const unsigned int keyARROWRIGHT = 74U;
    const unsigned int keyPAD0       = 75U;
    const unsigned int keyPAD1       = 76U;
    const unsigned int keyPAD2       = 77U;
    const unsigned int keyPAD3       = 78U;
    const unsigned int keyPAD4       = 79U;
    const unsigned int keyPAD5       = 80U;
    const unsigned int keyPAD6       = 81U;
    const unsigned int keyPAD7       = 82U;
    const unsigned int keyPAD8       = 83U;
    const unsigned int keyPAD9       = 84U;
    const unsigned int keyPADADD     = 85U;
    const unsigned int keyPADSUB     = 86U;
    const unsigned int keyPADMUL     = 87U;
    const unsigned int keyPADDIV     = 88U;
#endif

    const double PI = 3.14159265358979323846;   //!< Definition of the mathematical constant PI

    // Definition of a 10x13 font (small size).
    const unsigned int font10x13[256*10*13/32] = {
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80100c0,
      0x68000300,0x801,0xc00010,0x100c000,0x68100,0x100c0680,0x2,0x403000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x0,0x0,0x0,0x0,0x0,0x4020120,
      0x58120480,0x402,0x1205008,0x2012050,0x58080,0x20120581,0x40000001,0x804812,0x2000000,0x0,0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x140,0x80000,0x200402,0x800000,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x7010,0x7000000,0x8000200,0x20000,0xc0002000,0x8008,0x0,0x0,0x0,0x0,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x80000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x80100c0,0x68000480,0x1001,
      0xc00010,0x1018000,0x68100,0x100c0680,0x4,0x403000,0x1020000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,0x28081883,0x200801,
      0x2a00000,0x10,0x1c0201c0,0x70040f80,0xc0f81c07,0x0,0x70,0x3e0303c0,0x3c3c0f83,0xe03c2107,0xe08810,0x18c31070,0x3c0703c0,
      0x783e0842,0x22222208,0x83e04010,0x1008000,0x4000200,0x20001,0x2002,0x408008,0x0,0x0,0x100000,0x0,0x1008,0x2000000,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20080,0x38000880,0x8078140f,0x81c00000,0x3e000,0xc020180,0x60080001,0xe0000002,0xc00042,0x108e2010,
      0xc0300c0,0x300c0303,0xf83c3e0f,0x83e0f81c,0x701c070,0x3c0c41c0,0x701c0701,0xc0001d08,0x42108421,0x8820088,0x4020120,0x58140480,
      0x802,0x1205008,0x3014050,0xc058080,0x20120581,0x40000002,0x804814,0x2020050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,
      0x281e2484,0x80200801,0x1c02000,0x10,0x22060220,0x880c0801,0x82208,0x80000001,0x20008,0x41030220,0x40220802,0x402102,0x209010,
      0x18c31088,0x22088220,0x80080842,0x22222208,0x80204010,0x1014000,0x200,0x20001,0x2000,0x8008,0x0,0x0,0x100000,0x0,0x1008,
      0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x40000500,0x80800010,0x40200000,0x41000,0x12020040,0x10000003,0xa0000006,
      0x12000c4,0x31014000,0xc0300c0,0x300c0302,0x80402008,0x2008008,0x2008020,0x220c4220,0x88220882,0x20002208,0x42108421,0x8820088,
      0x0,0x300,0x0,0x0,0x0,0x14000000,0x0,0x200200,0x0,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xfc282504,0x80001000,
      0x82a02000,0x20,0x22020020,0x8140802,0x102208,0x80801006,0x18008,0x9c848220,0x80210802,0x802102,0x20a010,0x15429104,0x22104220,
      0x80080842,0x22221405,0x404008,0x1022000,0x703c0,0x381e0701,0xc0783c02,0xc09008,0x1d83c070,0x3c078140,0x381c0882,0x21242208,
      0x81e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,0x40220500,0x80800027,0x20e02800,0x9c800,0x12020040,
      0x20000883,0xa0200002,0x120a044,0x11064010,0x12048120,0x48120484,0x80802008,0x2008008,0x2008020,0x210a4411,0x4411044,0x10884508,
      0x42108421,0x503c0b0,0x1c0701c0,0x701c0707,0x70381c07,0x1c07008,0x2008020,0x20f01c0,0x701c0701,0xc0201c08,0x82208822,0x883c088,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x50281903,0x20001000,0x80802000,0x20,0x22020040,0x30240f03,0xc0101c08,0x80801018,
      0x1fc06010,0xa48483c0,0x80210f03,0xe0803f02,0x20c010,0x15429104,0x22104220,0x70080841,0x41540805,0x804008,0x1041000,0x8220,
      0x40220881,0x882202,0x40a008,0x12422088,0x22088180,0x40100882,0x21241408,0x80201008,0x2031000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x20280,0x401c0200,0x700028,0x21205000,0x92800,0xc1fc080,0x10000883,0xa0200002,0x1205049,0x12c19010,0x12048120,0x48120484,
      0xf0803c0f,0x3c0f008,0x2008020,0x790a4411,0x4411044,0x10504908,0x42108421,0x5022088,0x2008020,0x8020080,0x88402208,0x82208808,
      0x2008020,0x1e088220,0x88220882,0x20002608,0x82208822,0x8822088,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x501c0264,
      0xa0001000,0x8001fc00,0x7000020,0x22020080,0x83e0082,0x20202207,0x80000020,0x1020,0xa4848220,0x80210802,0x9c2102,0x20c010,
      0x12425104,0x3c1043c0,0x8080841,0x41540802,0x804008,0x1000000,0x78220,0x40220f81,0x882202,0x40c008,0x12422088,0x22088100,
      0x60100881,0x41540805,0x406008,0x1849000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0xf0140200,0x880028,0x20e0a03f,0x709c800,
      0x201c0,0x60000881,0xa0000007,0xc0284b,0x122eb020,0x12048120,0x48120487,0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,
      0x10204908,0x42108421,0x2022088,0x1e0781e0,0x781e0787,0xf8403e0f,0x83e0f808,0x2008020,0x22088220,0x88220882,0x21fc2a08,0x82208822,
      0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xf80a0294,0x40001000,0x80002000,0x20,0x22020100,0x8040082,0x20202200,
      0x80000018,0x1fc06020,0xa48fc220,0x80210802,0x842102,0x20a010,0x12425104,0x20104240,0x8080841,0x41541402,0x1004008,0x1000000,
      0x88220,0x40220801,0x882202,0x40a008,0x12422088,0x22088100,0x18100881,0x41540805,0x801008,0x2046000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x20280,0x401c0f80,0x80880028,0x20005001,0x94800,0x20000,0x880,0xa0000000,0x5015,0x4215040,0x3f0fc3f0,0xfc3f0fc8,
      0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,0x10505108,0x42108421,0x203c088,0x22088220,0x88220888,0x80402008,0x2008008,
      0x2008020,0x22088220,0x88220882,0x20002a08,0x82208822,0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xa00a0494,0x60001000,
      0x80002004,0x8020,0x22020200,0x88040882,0x20402201,0x801006,0x18000,0x9f084220,0x40220802,0x442102,0x209010,0x10423088,0x20088220,
      0x8080840,0x80882202,0x2004008,0x1000000,0x88220,0x40220881,0x882202,0x409008,0x12422088,0x22088100,0x8100880,0x80881402,
      0x1001008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0x40220200,0x80700027,0x20002801,0x92800,0x1fc000,0x980,
      0xa0000000,0xa017,0x84417840,0x21084210,0x84210848,0x80402008,0x2008008,0x2008020,0x2208c220,0x88220882,0x20882208,0x42108421,
      0x2020088,0x22088220,0x88220888,0xc8402208,0x82208808,0x2008020,0x22088220,0x88220882,0x20203208,0x82208822,0x2022020,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xa03c0463,0x90000801,0x2004,0x8040,0x1c0703e0,0x70040701,0xc0401c06,0x801001,0x20020,
      0x400843c0,0x3c3c0f82,0x3c2107,0x1c0881e,0x10423070,0x20070210,0xf0080780,0x80882202,0x3e04004,0x1000000,0x783c0,0x381e0701,
      0x782202,0x408808,0x12422070,0x3c078100,0x700c0780,0x80882202,0x1e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,
      0xf8000200,0x80080010,0x40000001,0x41000,0x0,0xe80,0xa0000000,0x21,0x8e21038,0x21084210,0x84210848,0xf83c3e0f,0x83e0f81c,
      0x701c070,0x3c08c1c0,0x701c0701,0xc0005c07,0x81e0781e,0x20200b0,0x1e0781e0,0x781e0787,0x30381c07,0x1c07008,0x2008020,0x1c0881c0,
      0x701c0701,0xc0201c07,0x81e0781e,0x203c020,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x801,0x4,0x40,0x0,0x0,0x0,0x1000,
      0x0,0x3c000000,0x0,0x0,0x0,0x0,0x10000,0x0,0x0,0x4004,0x1000000,0x0,0x0,0x80000,0x400000,0x0,0x20008000,0x0,0x4,0x1008,0x2000000,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x8008000f,0x80000000,0x3e000,0x0,0x800,0xa0000400,0x0,0x0,0x0,0x0,0x80000,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100000,0x0,0x0,0x0,0x0,0x2000,0x0,0x4020040,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,
      0x402,0x8,0x40,0x0,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x7004,0x70000fc,0x0,0x0,0x700000,0x800000,0x0,0x20008000,
      0x0,0x4,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x80f00000,0x0,0x0,0x0,0x800,0xa0001800,0x0,0x0,0x0,0x0,
      0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x4020040
    };

    // Definition of a 12x24 font (normal size).
    const unsigned int font12x24[12*24*256/32] = {
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x19,0x80000000,0x198000,0x0,0x0,0x0,0x0,
      0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc001806,0xc81980,0x60000000,0xc001806,0x1980c00,0x18060198,0xc80c,
      0x180600,0xc8198000,0xc001,0x80601980,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x600300f,0x1301980,0x90000000,0x600300f,0x1980600,0x300f0198,0x13006,0x300f01,0x30198000,0x6003,
      0xf01980,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x60000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7007,0x3c0000,0x3006019,
      0x80000000,0x90000000,0x3006019,0x80000300,0x60198000,0x3,0x601980,0x0,0x3006,0x1980000,0x60000000,0x0,0x0,0xe0000000,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000000,
      0x0,0x0,0x0,0x0,0x0,0xc800019,0x80000000,0x198000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x1001,0x420000,0x0,0x0,0x90000000,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000c06,0xc80001,0x10000000,0x18000c06,0x1800,0xc060000,0xc818,0xc0600,0xc8000000,
      0x18000,0xc0600000,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80660207,0x800f8060,0x300c004,0x0,0x6,
      0xe00703f,0x3f00383,0xf80f07fc,0x1f01f000,0x0,0xf8,0x607f,0x7c7e07,0xfe7fe0f8,0x6063fc1f,0x86066007,0xe7060f0,0x7f80f07f,
      0x81f8fff6,0x6606c03,0x70ee077f,0xe0786000,0xf0070000,0xc000060,0xc0,0x3e000,0x60006003,0x600fc00,0x0,0x0,0x0,0x0,0x0,0x3c0603,
      0xc0000000,0x7800000,0xf0000,0x0,0xf00001f,0x80001fe0,0x7fe000,0x0,0x0,0x0,0x168fe609,0x0,0x90e07,0x6000,0x3c000e,0x70000f8,
      0x1980001f,0x0,0x1f8,0xf00000f,0xf00180,0xfe000,0xe00e,0x1001,0x20060,0x6006006,0x600600,0x600fe07c,0x7fe7fe7f,0xe7fe3fc3,
      0xfc3fc3fc,0x7e07060f,0xf00f00,0xf00f0000,0xf360660,0x6606606e,0x76001e0,0xc00180f,0x1681981,0x10000000,0xc00180f,0x1980c00,
      0x180f0198,0x3801680c,0x180f01,0x68198000,0xc001,0x80f01980,0x18600198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,
      0x8044020c,0xc01f8060,0x2004004,0x0,0xc,0x3f81f07f,0x87f80383,0xf81f87fc,0x3f83f800,0x0,0x1fc,0x780607f,0x81fe7f87,0xfe7fe1fc,
      0x6063fc1f,0x860c6007,0xe7061f8,0x7fc1f87f,0xc3fcfff6,0x6606c03,0x30c6067f,0xe0783000,0xf00d8000,0x6000060,0xc0,0x7e000,0x60006003,
      0x600fc00,0x0,0x0,0xc00,0x0,0x0,0x7c0603,0xe0000000,0xfc00000,0x1f0000,0x0,0x900003f,0xc0003fe0,0x7fe000,0x0,0x0,0x0,0x1302660f,
      0x0,0xf0606,0x6004,0x7e0006,0x60601f8,0x19800001,0x80000000,0x1f8,0x19800010,0x81080300,0x3f2000,0x2011,0x1001,0x1c0060,0x6006006,
      0x600600,0x601fe1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f87061f,0x81f81f81,0xf81f8000,0x3fa60660,0x66066066,0x66003f0,0x6003009,
      0x1301981,0x10000000,0x6003009,0x1980600,0x30090198,0x1f013006,0x300901,0x30198000,0x6003,0x901980,0x30600198,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc0f8c,0xc0180060,0x6006044,0x40000000,0xc,0x3181b041,0xc41c0783,0x388018,
      0x71c71800,0x0,0x106,0x18c0f061,0xc38261c6,0x600384,0x60606001,0x86186007,0xe78630c,0x60e30c60,0xe7040606,0x630cc03,0x39c30c00,
      0xc0603000,0x3018c000,0x3000060,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,0x60000000,0x18400000,0x180000,
      0x0,0x19800070,0x40003600,0xc000,0x0,0x0,0x0,0x25a06,0x0,0x6030c,0x4,0xe20007,0xe060180,0xf000,0x80000000,0xf0000,0x10800000,
      0x80080600,0x7f2000,0x2020,0x80001001,0x20000,0xf00f00f,0xf00f00,0x601b0382,0x60060060,0x6000600,0x60060060,0x61c78630,0xc30c30c3,
      0xc30c000,0x30e60660,0x66066063,0xc600738,0x3006019,0x80000000,0xe0000000,0x3006019,0x80000300,0x60198000,0x3e000003,0x601980,
      0x0,0x3006,0x1980000,0x60600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc1fcc,0xc0180060,0x6006035,0x80000000,
      0x18,0x71c03000,0xc00c0583,0x300018,0x60c60c00,0x0,0x6,0x3060f060,0xc30060c6,0x600300,0x60606001,0x86306007,0x9e78670e,0x60670e60,
      0x66000606,0x630c606,0x19830c01,0xc0601800,0x30306000,0x60,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,
      0x60000000,0x18000000,0x300000,0x0,0x78060,0x6600,0x1c000,0x300c,0x39819c0,0x0,0x25a00,0x0,0x30c,0x4,0xc00003,0xc060180,0x30c1f,
      0x80000000,0x30c000,0x10800001,0x80700000,0x7f2000,0x2020,0x80001001,0x20060,0xf00f00f,0xf00f00,0xf01b0300,0x60060060,0x6000600,
      0x60060060,0x60c78670,0xe70e70e7,0xe70e000,0x70c60660,0x66066063,0xc7f8618,0x0,0x0,0x0,0x0,0x0,0x0,0x7000000,0x0,0x0,0x0,
      0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x87ff3a4c,0xc0180060,0x400600e,0x600000,0x18,0x60c03000,
      0xc00c0d83,0x700018,0x60c60c00,0x20,0x400006,0x3060f060,0xc6006066,0x600600,0x60606001,0x86606006,0x966c6606,0x60660660,0x66000606,
      0x630c666,0xf019801,0x80601800,0x30603000,0x1f06f,0xf01ec0,0xf03fe1ec,0x6703e01f,0x61c0c06,0xdc6701f0,0x6f01ec0c,0xe1f87fc6,
      0xc60cc03,0x71c60c7f,0xc0600600,0x60000000,0x30000000,0x300000,0x40040,0x88060,0x6600,0x18000,0x300c,0x1981980,0x0,0x2421f,
      0x80003ce0,0x7fc198,0x601f,0xc02021,0x980600c0,0x40230,0x80000000,0x402000,0x19806003,0x80006,0xc7f2000,0x2020,0x80001001,
      0x420060,0xf00f00f,0xf00f00,0xf01b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x6606208,0x60e60660,0x66066061,
      0x987fc670,0x1f01f01f,0x1f01f01,0xf039c0f0,0xf00f00f,0xf03e03,0xe03e03e0,0x1f06701f,0x1f01f01,0xf01f0060,0x1e660c60,0xc60c60c6,
      0xc6f060c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x7ff3207,0x8c0c0000,0xc00300e,0x600000,0x30,0x60c03000,
      0xc01c0983,0xf0600030,0x31860c06,0x6001e0,0x78000e,0x23e1f861,0xc6006066,0x600600,0x60606001,0x86c06006,0x966c6606,0x60660660,
      0xe7000606,0x630c666,0xf01f803,0x600c00,0x30000000,0x3f87f,0x83f83fc3,0xf83fe3fc,0x7f83e01f,0x6380c07,0xfe7f83f8,0x7f83fc0d,
      0xf3fc7fc6,0xc71cc03,0x3183187f,0xc0600600,0x60000000,0xff806000,0x300000,0x40040,0x88070,0x6600,0x60030060,0x6001818,0x1883180,
      0x0,0x2423f,0xc0007ff0,0x607fc1f8,0x603f,0x80c01fc1,0xf80601e0,0x5f220,0x80420000,0x5f2000,0xf006006,0x80006,0xc7f2000,0x2020,
      0x82107c07,0xc03c0060,0x1f81f81f,0x81f81f80,0xf03b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x660671c,0x61660660,
      0x66066061,0xf860e6c0,0x3f83f83f,0x83f83f83,0xf87fe3f8,0x3f83f83f,0x83f83e03,0xe03e03e0,0x3f87f83f,0x83f83f83,0xf83f8060,
      0x3fc60c60,0xc60c60c3,0x187f8318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x883200,0x300c0000,0xc003035,0x80600000,
      0x30,0x66c03001,0xc0f81983,0xf86f0030,0x1f071c06,0x600787,0xfe1e001c,0x6261987f,0x86006067,0xfe7fc600,0x7fe06001,0x87c06006,
      0xf6646606,0x60e6067f,0xc3e00606,0x61986f6,0x600f007,0x600c00,0x30000000,0x21c71,0x830831c3,0x1c06031c,0x71c06003,0x6700c06,
      0x6671c318,0x71831c0f,0x16040c06,0xc318606,0x1b031803,0x80600600,0x60000000,0x30009000,0x300000,0x40040,0x7003e,0x67e0,0x90070090,
      0x9001818,0x8c3100,0x0,0x60,0x4000e730,0x900380f0,0x6034,0x80c018c7,0xfe060338,0xb0121,0x80c60000,0x909000,0x6008,0x1080006,
      0xc3f2000,0x2011,0x3180060,0x60060e0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0x60664660,0x66066066,
      0x66063b8,0x62660660,0x66066060,0xf06066c0,0x21c21c21,0xc21c21c2,0x1c466308,0x31c31c31,0xc31c0600,0x60060060,0x31871c31,0x83183183,
      0x18318000,0x71860c60,0xc60c60c3,0x18718318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1981a00,0xe03e0000,0xc003044,
      0x40600000,0x60,0x66c03001,0x80f03182,0x1c7f8030,0x3f83fc06,0x601e07,0xfe078038,0x6661987f,0x86006067,0xfe7fc61e,0x7fe06001,
      0x87e06006,0x66666606,0x7fc6067f,0x81f80606,0x61986f6,0x6006006,0x600600,0x30000000,0xc60,0xc60060c6,0xc06060c,0x60c06003,
      0x6e00c06,0x6660c60c,0x60c60c0e,0x6000c06,0xc318666,0x1f031803,0x600600,0x603c2000,0x30016800,0x1fe0000,0x1f81f8,0x1c1f,0x804067e1,
      0x68060168,0x16800810,0xc42300,0x0,0x60,0x20c331,0x68030060,0x6064,0x3fc1040,0xf006031c,0xa011e,0x818c7fe0,0x909000,0x7fe1f,
      0x80f00006,0xc0f2060,0xf80e,0x18c0780,0x780781c0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0xfc666660,
      0x66066066,0x66061f0,0x66660660,0x66066060,0x606066e0,0xc00c00,0xc00c00c0,0xc066600,0x60c60c60,0xc60c0600,0x60060060,0x60c60c60,
      0xc60c60c6,0xc60c000,0x61c60c60,0xc60c60c3,0x1860c318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1980f81,0x80373000,
      0xc003004,0x7fe0001,0xf0000060,0x60c03003,0x183180,0xc71c060,0x3181ec00,0x7000,0xe070,0x66619860,0xc6006066,0x60061e,0x60606001,
      0x87606006,0x66626606,0x7f860661,0xc01c0606,0x6198696,0xf00600e,0x600600,0x30000000,0x1fc60,0xc60060c7,0xfc06060c,0x60c06003,
      0x7c00c06,0x6660c60c,0x60c60c0c,0x7f00c06,0xc3b8666,0xe01b007,0x3c00600,0x3c7fe000,0xff03ec00,0x1fe0000,0x40040,0xe001,0xc0806603,
      0xec0e03ec,0x3ec00010,0x0,0x60000000,0x7f,0x10c3f3,0xec070060,0x6064,0x3fc1040,0x6000030c,0xa0100,0x3187fe1,0xf09f1000,0x7fe00,
      0x6,0xc012060,0x0,0xc63c03,0xc03c0380,0x19819819,0x81981981,0x98330600,0x60060060,0x6000600,0x60060060,0xfc662660,0x66066066,
      0x66060e0,0x6c660660,0x66066060,0x6060e630,0x1fc1fc1f,0xc1fc1fc1,0xfc3fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6,
      0xc60c7fe,0x62c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe02c6,0x3c633000,0xc003004,
      0x7fe0001,0xf00000c0,0x60c03006,0xc6180,0xc60c060,0x60c00c00,0x7000,0xe060,0x66639c60,0x66006066,0x600606,0x60606001,0x86306006,
      0x66636606,0x60060660,0xc0060606,0x61f8696,0xf00600c,0x600300,0x30000000,0x3fc60,0xc60060c7,0xfc06060c,0x60c06003,0x7c00c06,
      0x6660c60c,0x60c60c0c,0x1f80c06,0xc1b0666,0xe01b00e,0x3c00600,0x3c43c000,0x3007de00,0x600000,0x40040,0x30000,0x61006607,0xde0c07de,
      0x7de00000,0x0,0xf07fefff,0x1f,0x8008c3f7,0xde0e0060,0x6064,0xc01047,0xfe00018c,0xb013f,0x86300061,0xf0911000,0x6000,0x6,
      0xc012060,0x3f,0x8063c0cc,0x3cc0c700,0x39c39c39,0xc39c39c1,0x98630600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,
      0x66061f0,0x78660660,0x66066060,0x607fc618,0x3fc3fc3f,0xc3fc3fc3,0xfc7fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6,
      0xc60c7fe,0x64c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe0260,0x6661b000,0xc003000,
      0x600000,0xc0,0x60c0300c,0xc7fe0,0xc60c060,0x60c01c00,0x1e07,0xfe078060,0x6663fc60,0x66006066,0x600606,0x60606001,0x86386006,
      0x6636606,0x60060660,0xe0060606,0x60f039c,0x1b806018,0x600300,0x30000000,0x70c60,0xc60060c6,0x6060c,0x60c06003,0x7600c06,
      0x6660c60c,0x60c60c0c,0x1c0c06,0xc1b03fc,0xe01f01c,0xe00600,0x70000000,0x3007fc00,0x600000,0x40040,0x0,0x62006607,0xfc1807fc,
      0x7fc00000,0x0,0xf0000000,0x1,0xc004c307,0xfc1c0060,0x6064,0xc018c0,0x600000d8,0x5f200,0x3180060,0x50a000,0x6000,0x6,0xc012000,
      0x0,0xc601c0,0x4201c600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,0x66063b8,
      0x70660660,0x66066060,0x607f860c,0x70c70c70,0xc70c70c7,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,
      0x68c60c60,0xc60c60c1,0xf060c1f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3300260,0x6661e000,0xc003000,0x600000,
      0x180,0x71c03018,0xc7fe0,0xc60c0c0,0x60c01800,0x787,0xfe1e0060,0x6663fc60,0x630060c6,0x600306,0x60606001,0x86186006,0x661e70e,
      0x60070c60,0x60060606,0x60f039c,0x19806038,0x600180,0x30000000,0x60c60,0xc60060c6,0x6060c,0x60c06003,0x6700c06,0x6660c60c,
      0x60c60c0c,0xc0c06,0xc1b039c,0x1f00e018,0x600600,0x60000000,0x1803f800,0x600000,0x40040,0x39e00,0x63006603,0xf83803f8,0x3f800000,
      0x0,0x60000000,0x0,0xc00cc303,0xf8180060,0x6064,0xc01fc0,0x60060070,0x40200,0x18c0060,0x402000,0x6000,0x6,0xc012000,0x0,0x18c0140,
      0x2014600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0300,0x60060060,0x6000600,0x60060060,0x60c61e70,0xe70e70e7,0xe70e71c,0x60e60660,0x66066060,
      0x6060060c,0x60c60c60,0xc60c60c6,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,0x70c60c60,0xc60c60c0,
      0xe060c0e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x33022e0,0x6670c000,0xc003000,0x600600,0x60180,0x31803030,
      0x41c0184,0x1831c0c0,0x71c23806,0x6001e0,0x780000,0x62630c60,0xe38261c6,0x600386,0x60606043,0x860c6006,0x661e30c,0x60030c60,
      0x740e0607,0xe0f039c,0x31c06030,0x600180,0x30000000,0x61c71,0x830831c3,0x406031c,0x60c06003,0x6300c06,0x6660c318,0x71831c0c,
      0x41c0c07,0x1c0e039c,0x1b00e030,0x600600,0x60000000,0x1c41b00e,0x601cc0,0x401f8,0x45240,0xe1803601,0xb03001b0,0x1b000000,
      0x0,0x0,0x41,0xc008e711,0xb0300060,0x6034,0x80c02020,0x60060030,0x30c00,0xc60000,0x30c000,0x0,0x7,0x1c012000,0x0,0x3180240,
      0x6024608,0x30c30c30,0xc30c30c3,0xc630382,0x60060060,0x6000600,0x60060060,0x61c61e30,0xc30c30c3,0xc30c208,0x70c70e70,0xe70e70e0,
      0x6060068c,0x61c61c61,0xc61c61c6,0x1cc62308,0x30430430,0x43040600,0x60060060,0x31860c31,0x83183183,0x18318060,0x31c71c71,
      0xc71c71c0,0xe07180e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2203fc0,0x663f6000,0x6006000,0x600600,0x60300,
      0x3f81fe7f,0xc7f80187,0xf83f80c0,0x3f83f006,0x600020,0x400060,0x33e6067f,0xc1fe7f87,0xfe6001fe,0x6063fc7f,0x60e7fe6,0x660e3f8,
      0x6001f860,0x37fc0603,0xfc06030c,0x30c0607f,0xe06000c0,0x30000000,0x7fc7f,0x83f83fc3,0xfc0603fc,0x60c7fe03,0x61807c6,0x6660c3f8,
      0x7f83fc0c,0x7f80fc3,0xfc0e039c,0x3180607f,0xc0600600,0x60000000,0xfc0e00c,0x601986,0x66040040,0x4527f,0xc0803fe0,0xe07fe0e0,
      0xe000000,0x0,0x0,0x7f,0x80107ff0,0xe07fc060,0x603f,0x83fe0000,0x60060018,0xf000,0x420000,0xf0000,0x7fe00,0x7,0xfe012000,
      0x0,0x2100640,0xc0643f8,0x60660660,0x66066067,0xec3e1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f860e3f,0x83f83f83,0xf83f8000,
      0x5fc3fc3f,0xc3fc3fc0,0x606006fc,0x7fc7fc7f,0xc7fc7fc7,0xfcffe3f8,0x3fc3fc3f,0xc3fc7fe7,0xfe7fe7fe,0x3f860c3f,0x83f83f83,
      0xf83f8060,0x7f83fc3f,0xc3fc3fc0,0x607f8060,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2201f80,0x3c1e7000,0x6006000,
      0x600,0x60300,0xe01fe7f,0xc3f00183,0xe01f0180,0x1f01e006,0x600000,0x60,0x3006067f,0x807c7e07,0xfe6000f8,0x6063fc3e,0x6067fe6,
      0x660e0f0,0x6000f060,0x3bf80601,0xf806030c,0x60e0607f,0xe06000c0,0x30000000,0x1ec6f,0xf01ec0,0xf80601ec,0x60c7fe03,0x61c03c6,
      0x6660c1f0,0x6f01ec0c,0x3f007c1,0xcc0e030c,0x71c0c07f,0xc0600600,0x60000000,0x7804018,0xe01186,0x66040040,0x39e3f,0x80401fe0,
      0x407fe040,0x4000000,0x0,0x0,0x3f,0x203ce0,0x407fc060,0x601f,0x3fe0000,0x60060018,0x0,0x0,0x0,0x7fe00,0x6,0xe6012000,0x0,
      0x7e0,0x1807e1f0,0x60660660,0x66066066,0x6c3e07c,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7e060e0f,0xf00f00,0xf00f0000,0x8f01f81f,
      0x81f81f80,0x60600670,0x1ec1ec1e,0xc1ec1ec1,0xec79c0f0,0xf80f80f,0x80f87fe7,0xfe7fe7fe,0x1f060c1f,0x1f01f01,0xf01f0000,0x4f01cc1c,
      0xc1cc1cc0,0xc06f00c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x6006000,0x600,0x600,0x0,0x0,0x0,0x0,
      0x600000,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x600060,0x30000000,0x0,0x0,0xc,0x3,0x0,0x0,0x60000c00,0x0,
      0x0,0xc000,0x600600,0x60000000,0x18,0xc03100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f8,0x0,0x0,0x0,0x0,0x6,
      0x12000,0x2000000,0x40,0x20004000,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0xc06000c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x2004000,0xc00,0x0,0x0,0x0,0x0,0x0,0xc00000,
      0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0xc00,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x21c,0x3,0x0,0x0,0x60000c00,0x0,0x0,0xc000,
      0x7c0603,0xe0000000,0x10,0xc02300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f0,0x0,0x0,0x0,0x0,0x6,0x12000,0x1000000,
      0x40,0x7e004000,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc06000c0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x300c000,0xc00,0x0,0x0,0x0,0x0,0x0,0xc00000,0x0,0x7800000,0x0,
      0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x3f8,0x3e,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x3c0603,0xc0000000,
      0x10,0xfc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x60000,0x0,0x0,0x0,0x0,0x6,0x0,0x1000000,0x0,0x0,0x0,0x0,
      0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x80600380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffc,0x0,
      0x0,0x1f0,0x3c,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x600,0x0,0x0,0xf000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x6,0x0,0xe000000,0x0,0x0,0x0,0x0,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x3,0x80600380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };

    // Definition of a 16x32 font (large size).
    const unsigned int font16x32[16*32*256/32] = {
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70000e0,0x3c00730,0xe7001c0,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0x730,0x70000e0,0x3c00730,
      0xe700000,0x700,0xe003c0,0xe7000e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x18001c0,0x6600ff0,0xe7003e0,0x0,0x18001c0,0x6600e70,0x18001c0,0x6600e70,0xff0,0x18001c0,0x6600ff0,0xe700000,0x180,
      0x1c00660,0xe7001c0,0x0,0x0,0x0,0x380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,
      0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00380,
      0xc300ce0,0xe700630,0x0,0x1c00380,0xc300e70,0x1c00380,0xc300e70,0xce0,0x1c00380,0xc300ce0,0xe700000,0x1c0,0x3800c30,0xe700380,
      0x0,0x0,0x0,0x7c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x700000,0x0,0x0,0x0,0x7c007c00,0x3e000000,
      0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe000070,0x1800000,0xc60,0x0,0xe000070,0x1800000,0xe000070,
      0x1800000,0x0,0xe000070,0x1800000,0x0,0xe00,0x700180,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x800000,0x0,0x600600,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x3f0,0xfc0,0x0,0x7000000,0x38000000,0x1c0000,0xfc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,
      0x1801f00,0x0,0x0,0x1c,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7300000,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0xe700000,
      0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0x0,0xc000c00,0x43800000,0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0xf80,0x70000e0,0x3c00730,0xe700c60,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0xe000730,0x70000e0,0x3c00730,0xe700000,0x700,
      0xe003c0,0xe7000e0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300000,0x803c00,0x7c00180,
      0xc00300,0x1000000,0x0,0x1c,0x3c007c0,0xfc007e0,0xe01ff8,0x3f03ffc,0x7e007c0,0x0,0x0,0x7c0,0x1c0,0x7f8003f0,0x7f007ff8,0x7ff803f0,
      0x70381ffc,0xff0700e,0x7000783c,0x783807c0,0x7fc007c0,0x7fc00fc0,0x7fff7038,0x700ee007,0x780f780f,0x7ffc03f0,0x70000fc0,0x3c00000,
      0x3000000,0x38000000,0x1c0000,0x1fc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x1801f80,0x0,0x1f80000,
      0x7e,0x0,0x0,0x2400000,0xfc00000,0x7ff0000,0x7ffc0000,0x0,0x0,0x0,0x0,0xf30fb0c,0x2400000,0x0,0x240780f,0x1c0,0xfc,0x780f,
      0x18003f0,0xe700000,0x7c00000,0x0,0xff0,0x3c00000,0x78007c0,0xc00000,0xff80000,0xf80,0x7c00000,0xc000c00,0x18001c0,0x1c001c0,
      0x1c001c0,0x1c003e0,0x7fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007838,0x7c007c0,0x7c007c0,0x7c00000,0x7c67038,
      0x70387038,0x7038780f,0x70001fe0,0x30000c0,0x2400f30,0xe700c60,0x0,0x30000c0,0x2400e70,0x30000c0,0x2400e70,0xf700f30,0x30000c0,
      0x2400f30,0xe700000,0x300,0xc00240,0xe7000c0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,
      0x630018c,0x807e00,0xfe00180,0xc00300,0x1000000,0x0,0x38,0xff01fc0,0x3ff01ff0,0x1e01ff8,0x7f83ffc,0x1ff80ff0,0x0,0x0,0xff0,
      0x1f003e0,0x7fe00ff8,0x7fc07ff8,0x7ff80ff8,0x70381ffc,0xff0701c,0x7000783c,0x78381ff0,0x7fe01ff0,0x7fe01ff0,0x7fff7038,0x781ee007,
      0x3c1e380e,0x7ffc0380,0x380001c0,0x3c00000,0x1800000,0x38000000,0x1c0000,0x3c00000,0x380001c0,0xe01c00,0x3800000,0x0,0x0,
      0x0,0x7000000,0x0,0x0,0x1e0,0x18003c0,0x0,0x3fc0000,0x70,0x0,0x0,0x6600000,0x1ff00000,0x1fff0000,0x7ffc0000,0x0,0x0,0x0,0x0,
      0xcf0239c,0x3c00000,0x0,0x3c0380e,0x1c0,0x2001fe,0x380e,0x18007f8,0xe700000,0x8600000,0x0,0xff0,0x7e00000,0x8c00870,0x1800000,
      0x1ff80000,0x180,0xc600000,0xc000c00,0x38001c0,0x3e003e0,0x3e003e0,0x3e001c0,0x7fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,
      0x7fc07838,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x1fec7038,0x70387038,0x7038380e,0x70003ce0,0x1800180,0x6600cf0,0xe7007c0,0x0,
      0x1800180,0x6600e70,0x1800180,0x6600e70,0x7c00cf0,0x1800180,0x6600cf0,0xe700000,0x180,0x1800660,0xe700180,0x38000e70,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630030c,0x3f0e700,0x1e200180,0x1800180,0x21100000,0x0,
      0x38,0x1e7819c0,0x38781038,0x1e01c00,0xf080038,0x1c381c38,0x0,0x0,0x1878,0x7fc03e0,0x70e01e18,0x70e07000,0x70001e18,0x703801c0,
      0x707038,0x70007c7c,0x7c381c70,0x70701c70,0x70703830,0x1c07038,0x381ce007,0x1c1c3c1e,0x3c0380,0x380001c0,0x7e00000,0xc00000,
      0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,0x70c0000,0xe0,
      0x0,0x0,0xc300000,0x38300000,0x3c700000,0x3c0000,0x0,0x0,0x0,0x0,0xce022f4,0x1800000,0x0,0x1803c1e,0x1c0,0x2003c2,0x3c1e,
      0x1800e08,0x7e0,0x300000,0x0,0x7e00000,0xe700000,0x600030,0x3000000,0x3f980000,0x180,0x18200000,0xc000c00,0x1e0001c0,0x3e003e0,
      0x3e003e0,0x3e003e0,0xfe01e18,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70e07c38,0x1c701c70,0x1c701c70,0x1c700000,0x3c787038,
      0x70387038,0x70383c1e,0x70003870,0xc00300,0xc300ce0,0x380,0x0,0xc00300,0xc300000,0xc00300,0xc300000,0xfc00ce0,0xc00300,0xc300ce0,
      0x0,0xc0,0x3000c30,0x300,0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630031c,0xff8c300,
      0x1c000180,0x1800180,0x39380000,0x0,0x70,0x1c3801c0,0x203c001c,0x3e01c00,0x1c000038,0x381c3838,0x0,0x0,0x1038,0xe0e03e0,0x70703c08,
      0x70707000,0x70003808,0x703801c0,0x707070,0x70007c7c,0x7c383838,0x70383838,0x70387010,0x1c07038,0x381c700e,0x1e3c1c1c,0x780380,
      0x1c0001c0,0xe700000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,
      0x0,0xe000000,0xe0,0x0,0x1000100,0x3800,0x70100000,0x38700000,0x780000,0x1c0,0x7801ce0,0xe380000,0x0,0x2264,0x0,0x0,0x1c1c,
      0x0,0x200780,0x1c1c,0x1800c00,0x1818,0x7f00000,0x0,0x18180000,0xc300000,0x600070,0x0,0x7f980000,0x180,0x18300000,0xc000c00,
      0x3000000,0x3e003e0,0x3e003e0,0x3e003e0,0xee03c08,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,
      0x38380000,0x38387038,0x70387038,0x70381c1c,0x7fc03870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbc00000,0x0,0x0,0x0,0x0,0x0,0x0,
      0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0xe88c300,0x1c000180,0x38001c0,
      0xfe00180,0x0,0x70,0x1c3801c0,0x1c001c,0x6e01c00,0x1c000078,0x381c3818,0x0,0x40000,0x40000038,0x1c0607e0,0x70703800,0x70707000,
      0x70003800,0x703801c0,0x7070e0,0x70007c7c,0x7c383838,0x70383838,0x70387000,0x1c07038,0x381c700e,0xf780e38,0x700380,0x1c0001c0,
      0x1c380000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,
      0xe000000,0xe0,0x0,0x1000100,0x4400,0x70000000,0x38700000,0x700000,0xe0,0x7001c70,0xe380000,0x0,0x2264,0x0,0x0,0xe38,0x0,
      0x200700,0xe38,0x1800c00,0x300c,0xc300000,0x0,0x300c0000,0xc300180,0x6003c0,0x0,0x7f980000,0x180,0x18300000,0xc000c00,0x1800000,
      0x7e007e0,0x7e007e0,0x7e003e0,0xee03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,0x38380000,
      0x38387038,0x70387038,0x70380e38,0x7ff039f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x40000,0x0,0x0,0x38000000,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0x1c80e700,0x1c000180,0x38001c0,0x3800180,
      0x0,0xe0,0x381c01c0,0x1c001c,0x6e01c00,0x38000070,0x381c381c,0x0,0x3c0000,0x78000078,0x38030770,0x70707800,0x70387000,0x70007000,
      0x703801c0,0x7071c0,0x7000745c,0x7638701c,0x7038701c,0x70387000,0x1c07038,0x1c38718e,0x7700f78,0xf00380,0xe0001c0,0x381c0000,
      0x7e0,0x39e003e0,0x79c03f0,0x3ffc079c,0x39e01fc0,0xfe01c1e,0x3807778,0x39e007e0,0x39e0079c,0x73c07e0,0x7ff83838,0x701ce007,
      0x783c701c,0x1ffc01c0,0x18001c0,0x0,0x1c000100,0xe0,0x0,0x1000100,0x4200,0x70000000,0x70700100,0xf00100,0x10000e0,0x7000c70,
      0xc700000,0x0,0x2204,0x7e00000,0x1e380100,0x1ffc0f78,0x0,0xf80700,0xf78,0x1800e00,0x63e6,0x18300000,0x0,0x6fe60000,0xe700180,
      0xc00060,0x3838,0x7f980000,0x180,0x18300000,0xc000c00,0x18001c0,0x7700770,0x7700770,0x77007f0,0xee07800,0x70007000,0x70007000,
      0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1008,0x707c7038,0x70387038,0x70380f78,0x707039c0,0x7e007e0,0x7e007e0,
      0x7e007e0,0x1f3c03e0,0x3f003f0,0x3f003f0,0x1fc01fc0,0x1fc01fc0,0x7f039e0,0x7e007e0,0x7e007e0,0x7e00380,0x7ce3838,0x38383838,
      0x3838701c,0x39e0701c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6307fff,0x1c807e0c,0xe000180,
      0x30000c0,0x3800180,0x0,0xe0,0x381c01c0,0x1c001c,0xce01fe0,0x38000070,0x381c381c,0x3800380,0xfc0000,0x7e0000f0,0x30030770,
      0x70707000,0x70387000,0x70007000,0x703801c0,0x707380,0x700076dc,0x7638701c,0x7038701c,0x70387800,0x1c07038,0x1c3873ce,0x7f00770,
      0xe00380,0xe0001c0,0x700e0000,0x1ff8,0x3ff00ff0,0xffc0ff8,0x3ffc0ffc,0x3bf01fc0,0xfe01c3c,0x3807f78,0x3bf00ff0,0x3ff00ffc,
      0x77e0ff0,0x7ff83838,0x3838e007,0x3c783838,0x1ffc01c0,0x18001c0,0x0,0x7ff00380,0x1e0,0x0,0x1000100,0x4200,0x78000000,0x70700380,
      0xe00380,0x3800060,0xe000e30,0x1c600000,0x0,0x2204,0xff00000,0x7f7c0380,0x1ffc0770,0x1c0,0x3fc0700,0x18040770,0x1800780,0x4e12,
      0x18300104,0x0,0x4c320000,0x7e00180,0x1c00030,0x3838,0x7f980000,0x180,0x18302080,0xc000c00,0x18001c0,0x7700770,0x7700770,
      0x7700770,0x1ee07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c381c,0x705c7038,0x70387038,
      0x70380770,0x70383b80,0x1ff81ff8,0x1ff81ff8,0x1ff81ff8,0x3fbe0ff0,0xff80ff8,0xff80ff8,0x1fc01fc0,0x1fc01fc0,0xff83bf0,0xff00ff0,
      0xff00ff0,0xff00380,0xffc3838,0x38383838,0x38383838,0x3ff03838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x1c0,0x7fff,0x1c803c38,0xf000000,0x70000e0,0xfe00180,0x0,0x1c0,0x381c01c0,0x3c0078,0xce01ff0,0x39e000f0,0x1c38381c,0x3800380,
      0x3e07ffc,0xf8001f0,0x307b0770,0x70e07000,0x70387000,0x70007000,0x703801c0,0x707700,0x700076dc,0x7638701c,0x7038701c,0x70387e00,
      0x1c07038,0x1c3873ce,0x3e007f0,0x1e00380,0x70001c0,0x0,0x1038,0x3c381e18,0x1c7c1e3c,0x3801e3c,0x3c7801c0,0xe01c78,0x380739c,
      0x3c781c38,0x3c381c3c,0x7c21e10,0x7003838,0x3838700e,0x1ef03838,0x3c01c0,0x18001c0,0x0,0x7fe007c0,0x1c0,0x0,0x1000100,0x6400,
      0x7e000000,0x707007c0,0x1e007c0,0x7c00070,0xe000638,0x18600000,0x0,0x0,0x1e100000,0x73ce07c0,0x3c07f0,0x1c0,0x7240700,0x1ddc3ffe,
      0x1800de0,0x8c01,0x1870030c,0x0,0x8c310000,0x3c00180,0x3800030,0x3838,0x7f980000,0x180,0x183030c0,0xc000c00,0x430001c0,0x7700770,
      0x7700770,0x7700770,0x1ce07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1c38,0x70dc7038,
      0x70387038,0x703807f0,0x70383b80,0x10381038,0x10381038,0x10381038,0x21e71e18,0x1e3c1e3c,0x1e3c1e3c,0x1c001c0,0x1c001c0,0x1e383c78,
      0x1c381c38,0x1c381c38,0x1c380380,0x1c383838,0x38383838,0x38383838,0x3c383838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0x1e8000e0,0x1f000000,0x70000e0,0x39380180,0x0,0x1c0,0x3b9c01c0,0x3c07f0,0x18e01078,0x3bf800e0,
      0x7e0383c,0x3800380,0x1f807ffc,0x3f001c0,0x61ff0e38,0x7fc07000,0x70387ff0,0x7ff07000,0x7ff801c0,0x707f00,0x7000729c,0x7338701c,
      0x7070701c,0x70703fc0,0x1c07038,0x1e7873ce,0x1c003e0,0x3c00380,0x70001c0,0x0,0x1c,0x3c381c00,0x1c3c1c1c,0x3801c3c,0x383801c0,
      0xe01cf0,0x380739c,0x38381c38,0x3c381c3c,0x7801c00,0x7003838,0x3838700e,0xfe03c78,0x7801c0,0x18001c0,0x0,0x1c000c20,0xff8,
      0x0,0x1ff01ff0,0x3818,0x3fc00100,0x707e0c20,0x3c00c20,0xc200030,0xc000618,0x18c00000,0x0,0x0,0x1c000080,0xe1ce0c20,0x7803e0,
      0x1c0,0xe200700,0xff83ffe,0x1801878,0x9801,0x1cf0071c,0x7ffc0000,0x8c310000,0x7ffe,0x7000030,0x3838,0x3f980380,0x180,0xc6038e0,
      0x7f9c7f9c,0x3e1c01c0,0xe380e38,0xe380e38,0xe380f78,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,0x1c001c0,0xfe387338,0x701c701c,
      0x701c701c,0x701c0e70,0x719c7038,0x70387038,0x703803e0,0x70383b80,0x1c001c,0x1c001c,0x1c001c,0xe71c00,0x1c1c1c1c,0x1c1c1c1c,
      0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380000,0x3c383838,0x38383838,0x38383c78,0x3c383c78,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0xf800380,0x3f830000,0x70000e0,0x31080180,0x0,0x380,0x3b9c01c0,
      0x7807e0,0x38e00038,0x3c3800e0,0xff01c3c,0x3800380,0x7c000000,0x7c03c0,0x61870e38,0x7fc07000,0x70387ff0,0x7ff070fc,0x7ff801c0,
      0x707f80,0x7000739c,0x7338701c,0x7ff0701c,0x7fe00ff0,0x1c07038,0xe7073ce,0x1c003e0,0x3800380,0x38001c0,0x0,0x1c,0x381c3800,
      0x381c380e,0x380381c,0x383801c0,0xe01de0,0x380739c,0x3838381c,0x381c381c,0x7001e00,0x7003838,0x1c70718e,0x7e01c70,0xf00380,
      0x18001e0,0x1e000000,0x1c001bb0,0xff8,0x0,0x1000100,0xe0,0xff00300,0x707e1bb0,0x3801bb0,0x1bb00010,0x8000308,0x30c00000,0x0,
      0x0,0x1e0000c0,0xe1ce1bb0,0xf003e0,0x1c0,0x1c203ff8,0x63003e0,0x180181c,0x9801,0xfb00e38,0x7ffc0000,0x8fc10000,0x7ffe,0xe000860,
      0x3838,0x1f980380,0x180,0x7c01c70,0x1f001f0,0x1f003c0,0xe380e38,0xe380e38,0xe380e38,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,
      0x1c001c0,0xfe387338,0x701c701c,0x701c701c,0x701c07e0,0x731c7038,0x70387038,0x703803e0,0x70383980,0x1c001c,0x1c001c,0x1c001c,
      0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x387c3838,0x38383838,0x38381c70,
      0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc30,0x7f00e00,0x33c30000,0x70000e0,0x1007ffe,
      0x0,0x380,0x3b9c01c0,0xf00078,0x30e0001c,0x3c1c01c0,0x1c381fdc,0x0,0x70000000,0x1c0380,0x63030e38,0x70707000,0x70387000,0x700070fc,
      0x703801c0,0x707b80,0x7000739c,0x7338701c,0x7fc0701c,0x7fc001f0,0x1c07038,0xe703e5c,0x3e001c0,0x7800380,0x38001c0,0x0,0x7fc,
      0x381c3800,0x381c380e,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7001fc0,0x7003838,0x1c70718e,0x7c01c70,
      0xe01f00,0x180007c,0x7f8c0000,0x7fc03fb8,0x1c0,0x0,0x1000100,0x700,0x1f00600,0x70703fb8,0x7803fb8,0x3fb80000,0x8000000,0x180,
      0x0,0x0,0x1fc00060,0xe1ce3fb8,0xe001c0,0x1c0,0x1c203ff8,0xc1801c0,0x180c,0x9801,0x1c70,0xc0000,0x8cc10000,0x180,0xfe007c0,
      0x3838,0x7980380,0xff0,0xe38,0x3e003e00,0x3e000380,0xe380e38,0xe380e38,0xe380e38,0x38e07000,0x70007000,0x70007000,0x1c001c0,
      0x1c001c0,0x70387338,0x701c701c,0x701c701c,0x701c03c0,0x731c7038,0x70387038,0x703801c0,0x703838e0,0x7fc07fc,0x7fc07fc,0x7fc07fc,
      0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x38dc3838,0x38383838,0x38381c70,
      0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc60,0xf83878,0x71e30000,0x70000e0,0x1007ffe,
      0x7f0,0x380,0x381c01c0,0x1e0003c,0x60e0001c,0x381c01c0,0x381c079c,0x0,0x7c000000,0x7c0380,0x63031c1c,0x70307000,0x70387000,
      0x7000701c,0x703801c0,0x7071c0,0x7000739c,0x71b8701c,0x7000701c,0x71e00078,0x1c07038,0xe703e7c,0x7e001c0,0xf000380,0x38001c0,
      0x0,0x1ffc,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fc0,0x380739c,0x3838381c,0x381c381c,0x7000ff0,0x7003838,0x1ef03bdc,
      0x3800ee0,0x1e01f00,0x180007c,0x61fc0000,0x7fc07f3c,0x1c0,0x0,0x1000100,0x1800,0x780c00,0x70707f3c,0xf007f3c,0x7f3c0000,0x0,
      0x3c0,0x3ffcffff,0x0,0xff00030,0xe1fe7f3c,0x1e001c0,0x1c0,0x1c200700,0xc183ffe,0xe0c,0x9801,0x1ff038e0,0xc07f0,0x8c610000,
      0x180,0x0,0x3838,0x1980380,0x0,0x1ff0071c,0xe000e000,0xe0000f80,0x1c1c1c1c,0x1c1c1c1c,0x1c1c1e38,0x38e07000,0x70007000,0x70007000,
      0x1c001c0,0x1c001c0,0x703871b8,0x701c701c,0x701c701c,0x701c03c0,0x761c7038,0x70387038,0x703801c0,0x70703870,0x1ffc1ffc,0x1ffc1ffc,
      0x1ffc1ffc,0xfff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x389c3838,0x38383838,
      0x38380ee0,0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xfffc,0xbc60fc,0x70e30000,0x70000e0,
      0x180,0x7f0,0x700,0x381c01c0,0x3e0001c,0x7ffc001c,0x381c03c0,0x381c001c,0x0,0x1f807ffc,0x3f00380,0x63031ffc,0x70387000,0x70387000,
      0x7000701c,0x703801c0,0x7071e0,0x7000701c,0x71b8701c,0x7000701c,0x70f00038,0x1c07038,0x7e03e7c,0x77001c0,0xe000380,0x1c001c0,
      0x0,0x3c1c,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x70003f8,0x7003838,0xee03bdc,
      0x3c00ee0,0x3c00380,0x18000e0,0xf00000,0x1c007e7c,0x3c0,0x0,0x1000100,0x0,0x381800,0x70707e7c,0xe007e7c,0x7e7c0000,0x0,0x7c0,
      0x0,0x0,0x3f80018,0xe1fe7e7c,0x3c001c0,0x1c0,0x1c200700,0xc183ffe,0xf0c,0x8c01,0x38e0,0xc07f0,0x8c710000,0x180,0x0,0x3838,
      0x1980000,0x0,0x71c,0x7000f0,0x700f00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x3fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
      0x703871b8,0x701c701c,0x701c701c,0x701c07e0,0x7c1c7038,0x70387038,0x703801c0,0x7ff03838,0x3c1c3c1c,0x3c1c3c1c,0x3c1c3c1c,
      0x3fff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x391c3838,0x38383838,0x38380ee0,
      0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfffc,0x9c01ce,0x70f60000,0x70000e0,0x180,
      0x0,0x700,0x381c01c0,0x780001c,0x7ffc001c,0x381c0380,0x381c003c,0x0,0x3e07ffc,0xf800380,0x63031ffc,0x70387000,0x70387000,
      0x7000701c,0x703801c0,0x7070f0,0x7000701c,0x71b8701c,0x7000701c,0x70700038,0x1c07038,0x7e03e7c,0xf7801c0,0x1e000380,0x1c001c0,
      0x0,0x381c,0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7000078,0x7003838,0xee03a5c,
      0x7c00fe0,0x78001c0,0x18001c0,0x0,0x1c003ef8,0x380,0x0,0x1000100,0x810,0x383000,0x70703ef8,0x1e003ef8,0x3ef80000,0x0,0x7c0,
      0x0,0x0,0x78000c,0xe1c03ef8,0x78001c0,0x1c0,0x1c200700,0x63001c0,0x18003f8,0x4e12,0x1c70,0xc0000,0x4c320000,0x180,0x0,0x3838,
      0x1980000,0x0,0xe38,0x700118,0x701e00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x7fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
      0x703871b8,0x701c701c,0x701c701c,0x701c0e70,0x7c1c7038,0x70387038,0x703801c0,0x7fc0381c,0x381c381c,0x381c381c,0x381c381c,
      0x78e03800,0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x3b1c3838,0x38383838,0x38380fe0,
      0x381c0fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1860,0x9c0186,0x707e0000,0x30000c0,0x180,
      0x0,0xe00,0x183801c0,0xf00001c,0xe0001c,0x181c0380,0x381c0038,0x0,0xfc0000,0x7e000000,0x61873c1e,0x70383800,0x70707000,0x7000381c,
      0x703801c0,0x707070,0x7000701c,0x70f83838,0x70003838,0x70780038,0x1c07038,0x7e03c3c,0xe3801c0,0x1c000380,0xe001c0,0x0,0x381c,
      0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01ef0,0x380739c,0x3838381c,0x381c381c,0x7000038,0x7003838,0xfe03e7c,0xfe007c0,
      0x70001c0,0x18001c0,0x0,0xe001ff0,0x380,0x0,0x1000100,0x162c,0x381800,0x30701ff0,0x1c001ff0,0x1ff00000,0x0,0x3c0,0x0,0x0,
      0x380018,0xe1c01ff0,0x70001c0,0x1c0,0x1c200700,0xff801c0,0x18000f0,0x63e6,0xe38,0x0,0x6c3e0000,0x0,0x0,0x3838,0x1980000,0x0,
      0x1c70,0xf0000c,0xf01c00,0x3c1e3c1e,0x3c1e3c1e,0x3c1e3c1c,0x70e03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x707070f8,
      0x38383838,0x38383838,0x38381c38,0x38387038,0x70387038,0x703801c0,0x7000381c,0x381c381c,0x381c381c,0x381c381c,0x70e03800,
      0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0380,0x3e1c3838,0x38383838,0x383807c0,0x381c07c0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18c0,0x9c0186,0x783c0000,0x38001c0,0x180,0x3800000,
      0x3800e00,0x1c3801c0,0x1e00003c,0xe00038,0x1c1c0780,0x381c0038,0x3800380,0x3c0000,0x78000000,0x61ff380e,0x70383808,0x70707000,
      0x7000381c,0x703801c0,0x40707078,0x7000701c,0x70f83838,0x70003838,0x70384038,0x1c07038,0x7e03c3c,0x1e3c01c0,0x3c000380,0xe001c0,
      0x0,0x383c,0x3c381c00,0x1c3c1c00,0x3801c3c,0x383801c0,0xe01c78,0x380739c,0x38381c38,0x3c381c3c,0x7000038,0x7003878,0x7c01e78,
      0x1ef007c0,0xf0001c0,0x18001c0,0x0,0xe000ee0,0x7800380,0xe380000,0x1001ff0,0x2242,0x40380c00,0x38700ee0,0x3c000ee0,0xee00000,
      0x0,0x0,0x0,0x0,0x380030,0xe1c00ee0,0xf0001c0,0x1c0,0xe200700,0xdd801c0,0x1800038,0x300c,0x71c,0x0,0x300c0000,0x0,0x0,0x3838,
      0x1980000,0x0,0x38e0,0xb0000c,0xb01c08,0x380e380e,0x380e380e,0x380e380e,0x70e03808,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
      0x707070f8,0x38383838,0x38383838,0x3838381c,0x38387038,0x70387038,0x703801c0,0x7000381c,0x383c383c,0x383c383c,0x383c383c,
      0x70e01c00,0x1c001c00,0x1c001c00,0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383878,0x38783878,0x387807c0,
      0x3c3807c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x18c0,0x10b801ce,0x3c3e0000,0x38001c0,0x180,
      0x3800000,0x3801c00,0x1e7801c0,0x3c002078,0xe02078,0x1c380700,0x1c3810f0,0x3800380,0x40000,0x40000380,0x307b380e,0x70701e18,
      0x70e07000,0x70001c1c,0x703801c0,0x60e0703c,0x7000701c,0x70f83c78,0x70003c70,0x703c70f0,0x1c03870,0x3c01c3c,0x3c1c01c0,0x78000380,
      0x7001c0,0x0,0x3c7c,0x3c381e18,0x1c7c1e0c,0x3801c3c,0x383801c0,0xe01c38,0x3c0739c,0x38381c38,0x3c381c3c,0x7001078,0x7803c78,
      0x7c01c38,0x1c780380,0x1e0001c0,0x18001c0,0x0,0x70c06c0,0x7000380,0xe300000,0x1000100,0x2142,0x70f00600,0x3c7006c0,0x780006c0,
      0x6c00000,0x0,0x0,0x0,0x0,0x10780060,0x73e206c0,0x1e0001c0,0x1c0,0x7240700,0x180c01c0,0x1800018,0x1818,0x30c,0x0,0x18180000,
      0x0,0x0,0x3c78,0x1980000,0x0,0x30c0,0x130000c,0x1301c18,0x380e380e,0x380e380e,0x380e380e,0x70e01e18,0x70007000,0x70007000,
      0x1c001c0,0x1c001c0,0x70e070f8,0x3c783c78,0x3c783c78,0x3c781008,0x7c783870,0x38703870,0x387001c0,0x70003a3c,0x3c7c3c7c,0x3c7c3c7c,
      0x3c7c3c7c,0x79f11e18,0x1e0c1e0c,0x1e0c1e0c,0x1c001c0,0x1c001c0,0x1c783838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383c78,0x3c783c78,
      0x3c780380,0x3c380380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x38c0,0x1ff800fc,0x1fee0000,
      0x1800180,0x180,0x3800000,0x3801c00,0xff01ffc,0x3ffc3ff0,0xe03ff0,0xff00700,0x1ff81fe0,0x3800380,0x0,0x380,0x3000780f,0x7ff00ff8,
      0x7fc07ff8,0x70000ffc,0x70381ffc,0x7fe0701c,0x7ff8701c,0x70781ff0,0x70001ff0,0x701c7ff0,0x1c01fe0,0x3c01c38,0x380e01c0,0x7ffc0380,
      0x7001c0,0x0,0x1fdc,0x3ff00ff0,0xffc0ffc,0x3800fdc,0x38383ffe,0xe01c3c,0x1fc739c,0x38380ff0,0x3ff00ffc,0x7001ff0,0x3f81fb8,
      0x7c01c38,0x3c3c0380,0x1ffc01c0,0x18001c0,0x0,0x3fc0380,0x7000380,0xc70718c,0x1000100,0x2244,0x7ff00200,0x1fff0380,0x7ffc0380,
      0x3800000,0x0,0x0,0x0,0x0,0x1ff000c0,0x7f7e0380,0x1ffc01c0,0x1c0,0x3fc3ffe,0x1c0,0x1800018,0x7e0,0x104,0x0,0x7e00000,0x7ffe,
      0x0,0x3fde,0x1980000,0x0,0x2080,0x3300018,0x3300ff0,0x780f780f,0x780f780f,0x780f780e,0xf0fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,
      0x1ffc1ffc,0x7fc07078,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x7ff01fe0,0x1fe01fe0,0x1fe001c0,0x70003bf8,0x1fdc1fdc,0x1fdc1fdc,
      0x1fdc1fdc,0x3fbf0ff0,0xffc0ffc,0xffc0ffc,0x3ffe3ffe,0x3ffe3ffe,0xff03838,0xff00ff0,0xff00ff0,0xff00000,0x3ff01fb8,0x1fb81fb8,
      0x1fb80380,0x3ff00380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x31c0,0x7e00078,0x7cf0000,0x1800180,
      0x0,0x3800000,0x3803800,0x3c01ffc,0x3ffc0fe0,0xe01fc0,0x3e00e00,0x7e00f80,0x3800380,0x0,0x380,0x18007007,0x7fc003f0,0x7f007ff8,
      0x700003f0,0x70381ffc,0x3f80701e,0x7ff8701c,0x707807c0,0x700007c0,0x701e1fc0,0x1c00fc0,0x3c01818,0x780f01c0,0x7ffc0380,0x3801c0,
      0x0,0xf9c,0x39e003e0,0x79c03f0,0x380079c,0x38383ffe,0xe01c1e,0x7c739c,0x383807e0,0x39e0079c,0x7000fc0,0x1f80f38,0x3801c38,
      0x781e0380,0x1ffc01c0,0x18001c0,0x0,0x1f80100,0xe000700,0x1c60718c,0x1000100,0x1e3c,0x1fc00100,0x7ff0100,0x7ffc0100,0x1000000,
      0x0,0x0,0x0,0x0,0xfc00080,0x3e3c0100,0x1ffc01c0,0x1c0,0xf83ffe,0x1c0,0x1800838,0x0,0x0,0x0,0x0,0x7ffe,0x0,0x3b9e,0x1980000,
      0x0,0x0,0x2300038,0x23003e0,0x70077007,0x70077007,0x70077007,0xe0fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007078,
      0x7c007c0,0x7c007c0,0x7c00000,0xc7c00fc0,0xfc00fc0,0xfc001c0,0x700039f0,0xf9c0f9c,0xf9c0f9c,0xf9c0f9c,0x1f1e03e0,0x3f003f0,
      0x3f003f0,0x3ffe3ffe,0x3ffe3ffe,0x7e03838,0x7e007e0,0x7e007e0,0x7e00000,0x63e00f38,0xf380f38,0xf380380,0x39e00380,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,0xc00300,0x0,0x3000000,0x3800,0x0,0x0,0x0,0x0,
      0x0,0x300,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0,0x0,0x0,0x0,0x0,0x380,0x3801c0,0x0,0x0,0x0,0x0,0x1c,0x0,0xe00000,
      0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1c0,0x18001c0,0x0,0x0,0xe000700,0x18600000,0x1000100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800ff0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0x1800000,0x0,0x6300070,0x6300000,0x0,
      0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000000,
      0x0,0x700,0x38000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,0xc00300,0x0,0x7000000,
      0x7000,0x0,0x0,0x0,0x0,0x0,0x700,0x0,0x0,0xf040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78,0x0,0x0,0x0,0x0,0x3f0,0x1c0fc0,0x0,0x0,
      0x0,0x0,0x1c,0x0,0xe00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1e0,0x18003c0,0x0,0x0,0xc000700,0x18c00000,0x1000000,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x18007e0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000,
      0x0,0x7f800e0,0x7f80000,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x700,0x38000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,
      0x0,0x600600,0x0,0x6000000,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x7fc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x0,
      0x3f0,0xfc0,0x0,0x0,0x0,0x0,0x838,0x0,0x1e00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0xf00,0xfc,0x1801f80,0x0,0x0,0x8008e00,0x30c00000,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000,
      0x0,0x3001c0,0x300000,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0xf00,0x38000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0xff0,0x0,0x1fc00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3e00,0x7c,0x1801f00,0x0,0x0,0x800fe00,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7c00000,0x0,0x3001fc,0x300000,
      0x0,0x0,0x0,0x3e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x3e00,0x38003e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfff8,0x0,0x0,0x0,0x7e0,0x0,0x1f000000,
      0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3c00,0x0,0x1800000,0x0,0x0,0x7800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00,0x38003c00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0 };

    // Definition of a 29x57 font (extra large size).
    const unsigned int font29x57[29*57*256/32] = {
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x781e00,0x0,0x0,0x7,0x81e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c0000,0xf8000,0x7e00000,0x0,0x7,
      0xc0000000,0x0,0x7c00,0xf80,0x7e000,0x0,0x7c00000,0xf80000,0x7e000000,0x0,0x0,0x1f00,0x3e0,0x1f800,0x0,0x0,0x0,0x3,0xe0000000,
      0x7c00003f,0x0,0xf8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x3c3c00,0x0,0x0,0x3,0xc3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0000,
      0x1f0000,0x7e00000,0xf838001f,0xf80001f,0xf0000000,0x0,0x3e00,0x1f00,0x7e000,0x3e1f000,0x3e00000,0x1f00000,0x7e00003e,0x1f000000,
      0x3e0,0xe0000f80,0x7c0,0x1f800,0x3e0e00,0x7c3e000,0x0,0x1,0xf0000000,0xf800003f,0x1f0f,0x800001f0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e7800,0x0,0x0,
      0x1,0xe7800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x1e0000,0xff00001,0xfe38001f,0xf80003f,
      0xf8000000,0x0,0x1e00,0x1e00,0xff000,0x3e1f000,0x1e00000,0x1e00000,0xff00003e,0x1f000000,0x7f8,0xe0000780,0x780,0x3fc00,0x7f8e00,
      0x7c3e000,0x0,0x0,0xf0000000,0xf000007f,0x80001f0f,0x800001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xef000,0x0,0x0,0x0,0xef000000,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000,0x3c0000,0x1e780003,0xfff8001f,0xf80003c,0x78000000,0x0,0xf00,0x3c00,0x1e7800,
      0x3e1f000,0xf00000,0x3c00001,0xe780003e,0x1f000000,0xfff,0xe00003c0,0xf00,0x79e00,0xfffe00,0x7c3e000,0x0,0x0,0x78000001,0xe00000f3,
      0xc0001f0f,0x800003c0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e000,0x0,0x0,0x0,0x7e000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x78000,0x780000,0x3c3c0003,0x8ff0001f,0xf800078,0x3c000000,0x0,0x780,0x7800,0x3c3c00,0x3e1f000,0x780000,0x7800003,0xc3c0003e,
      0x1f000000,0xe3f,0xc00001e0,0x1e00,0xf0f00,0xe3fc00,0x7c3e000,0x0,0x0,0x3c000003,0xc00001e1,0xe0001f0f,0x80000780,0x0,0x0,
      0x0,0x0,0x0,0x0,0x1f,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x7e000,0x0,0x0,0x0,0x7e000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc00,0x7e000,0xfe000,0x0,0x3c000,0xf00000,0x781e0003,
      0x83e0001f,0xf800070,0x1c000000,0x0,0x3c0,0xf000,0x781e00,0x3e1f000,0x3c0000,0xf000007,0x81e0003e,0x1f000000,0xe0f,0x800000f0,
      0x3c00,0x1e0780,0xe0f800,0x7c3e000,0x0,0x0,0x1e000007,0x800003c0,0xf0001f0f,0x80000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf8000000,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3fc00,0x1fe000,0x3ff800,0x0,0x0,0x0,0x0,0x0,0x70,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x78,0xf000000,0x0,0x0,0x780f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x3fc00,0x1fe000,0x3ffc00,0x0,0x0,0x0,0x0,0x0,0x70,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x3e000,0x3e00000,0x0,0x78,0x3c000000,0x0,0x1f000,0x3e0,
      0x3e000,0x0,0x1f000000,0x3e0000,0x3e000000,0x0,0x0,0x7c00,0xf8,0xf800,0x0,0x0,0x0,0xf,0x80000000,0x1f00001f,0x0,0x3e,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80000,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x781c0000,0x38,0xe000000,0x0,0x0,0x380e0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x39c00,0x1ce000,0x303e00,
      0x0,0x0,0x0,0x0,0x0,0x78,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,
      0x0,0x0,0xf80000,0x7c000,0x3e00000,0xf0380000,0x70,0x1c000000,0x0,0xf800,0x7c0,0x3e000,0x0,0xf800000,0x7c0000,0x3e000000,
      0x0,0x3c0,0xe0003e00,0x1f0,0xf800,0x3c0e00,0x0,0x0,0x7,0xc0000000,0x3e00001f,0x0,0x7c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0xff,0x0,
      0xf8,0xf8000,0x1c000,0x0,0x0,0x0,0x0,0x1f,0xc0000000,0x1ff8,0xff00,0x0,0x0,0x3fe000,0x0,0x1fc00001,0xfe000000,0x0,0x0,0x0,
      0x0,0x7f800,0x0,0x0,0x0,0xff00000,0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xf8000000,0xfe,0x0,0x7f80,0x0,0x0,0x0,0x0,0x0,
      0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x780000,0x1,0xe0000000,0x0,0x780000,0x3,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x3fc00,0x0,0x0,0x1fc000,0x0,0x0,0x0,0x1fc0,
      0x0,0xff000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe1c0000,0x1c,0x1c000000,0x0,0x0,0x1c1c0,0x0,0x0,0x0,0x0,0x1fe0000,
      0x0,0x0,0x1ff,0x1f0f8,0x0,0xff000,0x0,0x0,0x0,0x3f,0xff00000f,0x80000000,0xfe0,0x3f80,0xf00,0x0,0x0,0x0,0x1,0xf8000003,0xe0000000,
      0x1c00,0xe000,0xe00,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,
      0x7f0000,0x0,0x1fc07000,0x0,0x0,0x0,0x0,0x0,0x3f800,0x780000,0x78000,0x7f00001,0xfc38001f,0xf800070,0x1c000000,0x0,0x7800,
      0x780,0x7f000,0x3e1f000,0x7800000,0x780000,0x7f00003e,0x1f0003f0,0x7f0,0xe0001e00,0x1e0,0x1fc00,0x7f0e00,0x7c3e000,0x0,0x3,
      0xc0000000,0x3c00003f,0x80001f0f,0x80000078,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x1e078000,0x30000000,0x3ff,0xc00001e0,0xf0,
      0x78000,0x1c000,0x0,0x0,0x0,0x0,0x1e0007f,0xf000007e,0x1ffff,0x7ffe0,0x1f80,0x3ffff80,0xfff803,0xfffff800,0xfff80007,0xff800000,
      0x0,0x0,0x0,0x0,0x1ffe00,0x0,0xfe0003,0xfff80000,0x3ffe01ff,0xe00003ff,0xffe01fff,0xff0003ff,0xe01e0007,0x803ffff0,0xfff80,
      0x3c000fc0,0x7800001f,0x8003f07e,0x1e000f,0xfe0007ff,0xf00003ff,0x8007ffe0,0x1fff8,0x7fffffe,0xf0003c1,0xe000079e,0xf1f,0x1f3e0,
      0x1f01ff,0xfff8003f,0xf003c000,0x7fe0,0x3f00,0x0,0x3c0000,0x1,0xe0000000,0x0,0x780000,0xf,0xfe000000,0x78000,0x3c00,0xf000,
      0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xfc0000f0,0x3fe00,0x0,0x0,0xfff00,0x0,0x0,0x3fe000,
      0x0,0x0,0x0,0x1dc0,0x0,0x3fff00,0x0,0x3ffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff1c07ff,0x3c0f001e,0x3c000000,
      0x0,0x0,0x1e3c0,0xf80007c,0x0,0x780000,0x0,0xfff8000,0x3e00,0x1f00000,0x7ff,0xc001f0f8,0x0,0x3ffc00,0x0,0x0,0x0,0x3f,0xff00003f,
      0xe0000000,0x3ff8,0xffe0,0x1e00,0x0,0xfffc00,0x0,0x7,0xf800000f,0xf8000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,
      0x3f800001,0xfc00003f,0xf80000ff,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,
      0xfc00,0x3c001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x0,0x7ff8f0f0,0x3c0780,0x1e03c00,0xf01e000,0x783e0001,0xf01e0000,0xffe00,
      0x3c0000,0xf0000,0x7700001,0xfe38001f,0xf800070,0x1c000000,0x0,0x3c00,0xf00,0x77000,0x3e1f000,0x3c00000,0xf00000,0x7700003e,
      0x1f0000f8,0xc0007f8,0xe0000f00,0x3c0,0x1dc00,0x7f8e00,0x7c3e000,0x0,0x1,0xe0000000,0x7800003b,0x80001f0f,0x800000f0,0x1e0000,
      0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x780000,0x3c1e0000,0x1e070000,0x300001f0,0x7ff,0xc00001e0,0x1e0,0x7c000,0x1c000,0x0,0x0,0x0,0x0,0x3c000ff,0xf80007fe,
      0x3ffff,0x801ffff8,0x1f80,0x3ffff80,0x3fff803,0xfffff801,0xfffc000f,0xffc00000,0x0,0x0,0x0,0x0,0x7fff80,0x0,0xfe0003,0xffff0000,
      0xffff01ff,0xfc0003ff,0xffe01fff,0xff000fff,0xf01e0007,0x803ffff0,0xfff80,0x3c001f80,0x7800001f,0xc007f07e,0x1e001f,0xff0007ff,
      0xfc0007ff,0xc007fffc,0x3fffc,0x7fffffe,0xf0003c1,0xf0000f9e,0xf0f,0x8003e1e0,0x1e01ff,0xfff8003f,0xf001e000,0x7fe0,0x3f00,
      0x0,0x1e0000,0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x1fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x3de0,0x0,0x7fff80,0x0,0xfffff80,
      0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe7bc07ff,0x3e1f000f,0x78000000,0x0,0x0,0xf780,0x7800078,0x0,0x780000,0x180000,
      0x1fff8000,0x1e00,0x1e0003c,0xfff,0xc001f0f8,0x0,0x7ffe00,0x0,0x0,0x0,0x3f,0xff00007f,0xf0000000,0x3ffc,0xfff0,0x3c00,0x0,
      0x7fffc00,0x0,0x7,0xf800003f,0xfe000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xe00001ff,
      0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000fc00,0x3c003ffe,0x1fff0,
      0xfff80,0x7ffc00,0x3ffe000,0x0,0xfffce0f0,0x3c0780,0x1e03c00,0xf01e000,0x781e0001,0xe01e0000,0x3fff00,0x1e0000,0x1e0000,0xf780003,
      0xcf78001f,0xf800078,0x3c000000,0x0,0x1e00,0x1e00,0xf7800,0x3e1f000,0x1e00000,0x1e00000,0xf780003e,0x1f0000fc,0x7c000f3d,
      0xe0000780,0x780,0x3de00,0xf3de00,0x7c3e000,0x0,0x0,0xf0000000,0xf000007b,0xc0001f0f,0x800001e0,0x1e0000,0x3e1f00,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,
      0x3c1e0000,0x1e0f0000,0x300007fc,0xfff,0xc00001e0,0x1e0,0x3c000,0x1c000,0x0,0x0,0x0,0x0,0x3c001ff,0xfc001ffe,0x3ffff,0xc01ffffc,
      0x3f80,0x3ffff80,0x7fff803,0xfffff803,0xfffe001f,0xffe00000,0x0,0x0,0x0,0x0,0xffff80,0x7f800,0xfe0003,0xffff8001,0xffff01ff,
      0xff0003ff,0xffe01fff,0xff001fff,0xf01e0007,0x803ffff0,0xfff80,0x3c003f00,0x7800001f,0xc007f07f,0x1e003f,0xff8007ff,0xff000fff,
      0xe007ffff,0x7fffc,0x7fffffe,0xf0003c0,0xf0000f1e,0xf07,0x8003c1f0,0x3e01ff,0xfff8003f,0xf001e000,0x7fe0,0x7f80,0x0,0xe0000,
      0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,
      0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x3fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x78f0,0x0,0xffff80,0x0,0x3fffff80,0x1f,
      0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc7f80070,0x3e1f0007,0x70000000,0x0,0x0,0x7700,0x7c000f8,0x0,0x780000,0x180000,
      0x3fff8000,0x1f00,0x3e0003c,0x1f03,0xc001f0f8,0x0,0x703f00,0x0,0x0,0x0,0x3f,0xff0000f0,0xf8000000,0x303e,0xc0f8,0x7800,0x0,
      0xffffc00,0x0,0x7,0x3800003e,0x3e000000,0x1c00,0xe000,0x3c00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00000f,0xe00001ff,
      0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000fe00,0x3c007fff,0x3fff8,
      0x1fffc0,0xfffe00,0x7fff000,0x1,0xffffc0f0,0x3c0780,0x1e03c00,0xf01e000,0x781f0003,0xe01e0000,0x3fff80,0xe0000,0x3c0000,0x1e3c0003,
      0x8ff0001f,0xf80003c,0x78000000,0x0,0xe00,0x3c00,0x1e3c00,0x3e1f000,0xe00000,0x3c00001,0xe3c0003e,0x1f00007f,0xf8000e3f,0xc0000380,
      0xf00,0x78f00,0xe3fc00,0x7c3e000,0x0,0x0,0x70000001,0xe00000f1,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c0f0000,
      0x30000ffe,0xf80,0xc00001e0,0x3c0,0x1e000,0x101c040,0x0,0x0,0x0,0x0,0x78003f0,0x7e001ffe,0x3f807,0xe01f00fe,0x3f80,0x3ffff80,
      0x7e01803,0xfffff007,0xe03f003f,0x3f00000,0x0,0x0,0x0,0x0,0xfc0fc0,0x3ffe00,0xfe0003,0xffffc003,0xf81f01ff,0xff8003ff,0xffe01fff,
      0xff003f01,0xf01e0007,0x803ffff0,0xfff80,0x3c007e00,0x7800001f,0xc007f07f,0x1e007e,0xfc007ff,0xff801f83,0xf007ffff,0x800fc07c,
      0x7fffffe,0xf0003c0,0xf0000f0f,0x1e07,0xc007c0f8,0x7c01ff,0xfff8003c,0xf000,0x1e0,0xffc0,0x0,0xf0000,0x1,0xe0000000,0x0,0x780000,
      0x3e,0x0,0x78000,0x3c00,0xf000,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0x800000f0,0x1f80,
      0x0,0x0,0x7e0780,0x0,0x0,0x1f82000,0x0,0x0,0x0,0x7070,0x0,0x1f80f80,0x0,0x7fffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x1,0xc3f80070,0x3f3f0007,0xf0000000,0x0,0x0,0x7f00,0x3e001f0,0x0,0x780000,0x180000,0x7f018000,0xf80,0x7c0003c,0x3e00,
      0x4001f0f8,0xfe00,0x400f00,0x0,0x0,0x0,0x7f000000,0xe0,0x38000000,0x1e,0x38,0x7800,0x0,0x1ffe1c00,0x0,0x0,0x38000078,0xf000000,
      0x1c00,0xe000,0x7f800,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xf00001ff,0xffc03f81,0xf007ffff,0xc03ffffe,
      0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf800fe00,0x3c00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,
      0x3,0xf07fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x780f8007,0xc01e0000,0x7e0fc0,0xf0000,0x3c0000,0x1c1c0003,0x87f0001f,0xf80003f,
      0xf8000000,0x0,0xf00,0x3c00,0x1c1c00,0x3e1f000,0xf00000,0x3c00001,0xc1c0003e,0x1f00003f,0xc0000e1f,0xc00003c0,0xf00,0x70700,
      0xe1fc00,0x7c3e000,0x0,0x0,0x78000001,0xe00000e0,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c0f0001,0xff801e0f,
      0x1f00,0x1e0,0x3c0,0x1e000,0x3c1c1e0,0x0,0x0,0x0,0x0,0x78007c0,0x1f001f9e,0x3c001,0xf010003e,0x7780,0x3c00000,0xf800000,0xf007,
      0xc01f007c,0x1f80000,0x0,0x0,0x0,0x0,0xe003e0,0x7fff00,0x1ef0003,0xc007e007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x301e0007,
      0x80007800,0x780,0x3c00fc00,0x7800001f,0xe00ff07f,0x1e00f8,0x3e00780,0x1fc03e00,0xf807801f,0xc01f001c,0xf000,0xf0003c0,0xf0000f0f,
      0x1e03,0xc00f8078,0x780000,0xf0003c,0xf000,0x1e0,0x1f3e0,0x0,0x78000,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,
      0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0xf0,0xf80,0x0,0x0,0xf80180,0x0,0x0,0x1e00000,
      0x0,0x0,0x0,0xe038,0x0,0x3e00380,0x0,0xfe0f0000,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc0f00070,0x3b370003,0xe0000000,
      0x0,0x0,0x3e00,0x1e001e0,0x0,0x780000,0x180000,0x7c000000,0x780,0x780003c,0x3c00,0x0,0x7ffc0,0x780,0x0,0x0,0x3,0xffe00000,
      0x1c0,0x3c000000,0xe,0x38,0xf000,0x0,0x3ffe1c00,0x0,0x0,0x38000078,0xf000000,0x1c00,0xe000,0x7f000,0xf000,0x3de000,0x1ef0000,
      0xf780000,0x7bc00003,0xde00001e,0xf00003e7,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
      0xe0001e03,0xfc00fe00,0x3c01f007,0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x7,0xc01f80f0,0x3c0780,0x1e03c00,0xf01e000,0x78078007,
      0x801e0000,0x7803c0,0x78000,0x780000,0x380e0003,0x81e00000,0x1f,0xf0000000,0x0,0x780,0x7800,0x380e00,0x0,0x780000,0x7800003,
      0x80e00000,0x1ff,0x80000e07,0x800001e0,0x1e00,0xe0380,0xe07800,0x0,0x0,0x0,0x3c000003,0xc00001c0,0x70000000,0x780,0x1e0000,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x780000,0x3c1e0000,0x3c0e0007,0xfff01c07,0x1e00,0x1e0,0x780,0xf000,0x3e1c3e0,0x0,0x0,0x0,0x0,0xf0007c0,0x1f00181e,0x20000,
      0xf000001f,0xf780,0x3c00000,0x1f000000,0x1f00f,0x800f8078,0xf80000,0x0,0x0,0x0,0x0,0x8003e0,0x1fc0f80,0x1ef0003,0xc001e007,
      0x800101e0,0x7e003c0,0x1e00,0x7800,0x101e0007,0x80007800,0x780,0x3c00f800,0x7800001e,0xe00ef07f,0x801e00f0,0x1e00780,0x7c03c00,
      0x78078007,0xc01e0004,0xf000,0xf0003c0,0x78001e0f,0x1e03,0xe00f807c,0xf80000,0x1f0003c,0x7800,0x1e0,0x3e1f0,0x0,0x3c000,0x1,
      0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,
      0x1e,0xf0,0x780,0x0,0x0,0x1f00080,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x1e03c,0x0,0x3c00080,0x0,0xf80f0000,0x0,0x1f0000,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x3bf70003,0xe0000000,0x0,0x0,0x3e00,0x1f003e0,0x0,0x780000,0x180000,0x78000000,0x7c0,0xf80003c,
      0x3c00,0x0,0x1f01f0,0x780,0x0,0x0,0xf,0x80f80000,0x1c0,0x1c000000,0xe,0x38,0x1e000,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,0x7800000,
      0x1c00,0xe000,0x7fc00,0xf000,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x80007800,0x10078000,0x3c0000,
      0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00ff00,0x3c01e003,0xc00f001e,0x7800f0,0x3c00780,0x1e003c00,
      0x7,0x800f00f0,0x3c0780,0x1e03c00,0xf01e000,0x7807c00f,0x801e0000,0xf803c0,0x3c000,0xf00000,0x780f0000,0x0,0x7,0xc0000000,
      0x0,0x3c0,0xf000,0x780f00,0x0,0x3c0000,0xf000007,0x80f00000,0x7ff,0xc0000000,0xf0,0x3c00,0x1e03c0,0x0,0x0,0x0,0x0,0x1e000007,
      0x800003c0,0x78000000,0xf00,0x1e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c1e001f,0xfff03803,0x80001e00,0x1e0,0x780,0xf000,0xf9cf80,
      0x0,0x0,0x0,0x0,0xf000780,0xf00001e,0x0,0xf800000f,0xe780,0x3c00000,0x1e000000,0x1e00f,0x78078,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,
      0x3f003c0,0x1ef0003,0xc000f00f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,0x3c01f000,0x7800001e,0xe00ef07f,
      0x801e01f0,0x1e00780,0x3c07c00,0x78078003,0xc03e0000,0xf000,0xf0003c0,0x78001e0f,0x1e01,0xf01f003c,0xf00000,0x3e0003c,0x7800,
      0x1e0,0x7c0f8,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,
      0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x8,0x40,0x0,0x7e0000,0x7c00000,0x1,0xf00f0000,
      0x0,0x3e0000,0x0,0x3f,0xfc0,0xfc3f0,0xfc3f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,0xf003c0,0x0,0x0,0x180000,0xf8000000,
      0x3c0,0xf00003c,0x3c00,0x0,0x3c0078,0x7ff80,0x0,0x0,0x1e,0x3c0000,0x1c0,0x1c000000,0xe,0xf0,0x0,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,
      0x7800000,0x1c00,0xe000,0x3c00,0x0,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x8000f800,0x78000,0x3c0000,
      0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00ff00,0x3c03e003,0xc01f001e,0xf800f0,0x7c00780,0x3e003c00,
      0xf,0x800f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803c00f,0x1fffc0,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x307,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x781e003f,0xfff03803,
      0x80001e00,0x1e0,0xf80,0xf000,0x3dde00,0x0,0x0,0x0,0x0,0xf000f00,0x780001e,0x0,0x7800000f,0x1e780,0x3c00000,0x3e000000,0x3e00f,
      0x780f0,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,0x7c001e0,0x3ef8003,0xc000f00f,0x1e0,0xf003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,
      0x3c03e000,0x7800001e,0xf01ef07b,0xc01e01e0,0xf00780,0x3e07800,0x3c078003,0xe03c0000,0xf000,0xf0003c0,0x78001e0f,0x1e00,0xf01e003e,
      0x1f00000,0x3c0003c,0x7800,0x1e0,0x78078,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,
      0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0,
      0xe70000,0x7800000,0x1,0xe00f0000,0x0,0x3c0000,0x0,0x3f,0xfc0,0xfc1f0,0x1f83f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,
      0xf807c0,0x0,0x0,0x180000,0xf0000000,0x3e0,0x1f00003c,0x3e00,0x0,0x70001c,0x3fff80,0x0,0x0,0x38,0xe0000,0x1c0,0x1c000078,
      0x1c,0x1fe0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x7df000,0x3ef8000,0x1f7c0000,0xfbe00007,
      0xdf00003c,0x780003c7,0x8000f000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f780,
      0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0xf80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803e01f,0x1ffff8,0xf001e0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x0,0x0,0x1e0000,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x780000,0x3c1e0000,0x781e003e,0x30703803,0x80001e00,0x1e0,0xf00,0x7800,0xff800,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,
      0x0,0x7800000f,0x3c780,0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x2000000,0x800000,0x1e0,0x78000e0,0x3c78003,
      0xc000f01e,0x1e0,0xf803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x701cf07b,0xc01e01e0,0xf00780,0x1e07800,
      0x3c078001,0xe03c0000,0xf000,0xf0003c0,0x7c003e0f,0x1e00,0xf83e001e,0x1e00000,0x7c0003c,0x3c00,0x1e0,0xf807c,0x0,0x0,0x1fe0001,
      0xe1fc0000,0x7f00003,0xf8780007,0xf000003c,0x7f0,0x783f0,0x0,0x0,0x7800000,0x1e00000,0x3e0f8000,0xfc00007,0xf8000007,0xf00001fc,
      0xf,0xc0003fc0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0,0x1818000,
      0x7800000,0x1,0xe00f0000,0x0,0x7c0000,0x0,0x1f,0x80001f80,0x7c1f8,0x1f83e0,0x0,0x0,0x0,0x70,0x38c70007,0xf8000000,0x7f03,
      0xf0000000,0x0,0x780780,0x0,0x0,0xfe0000,0xf0000000,0x1e0,0x1e00003c,0x3f00,0x0,0xe07f0e,0x7fff80,0x0,0x0,0x70,0x70000,0x1c0,
      0x1c000078,0x3c,0x1fc0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x78f000,0x3c78000,0x1e3c0000,
      0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,
      0xf80f780,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0x1f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801e01e,0x1ffffc,
      0xf007e0,0x3fc000,0x1fe0000,0xff00000,0x7f800003,0xfc00001f,0xe0000fc0,0xfc00007f,0xfe0,0x7f00,0x3f800,0x1fc000,0x0,0x0,0x0,
      0x1,0xf000001f,0x80000ff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x1f80000,0x1fc1e000,0x0,0x0,0x0,0x0,0x1e1fc0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,
      0x781c007c,0x30003803,0x80001f00,0x1e0,0xf00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,0x0,0x7800000f,0x3c780,
      0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x1e000000,0xf00000,0x3e0,0xf0000e0,0x3c78003,0xc000f01e,0x1e0,0x7803c0,
      0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c0f8000,0x7800001e,0x701cf079,0xe01e01e0,0xf00780,0x1e07800,0x3c078001,0xe03c0000,
      0xf000,0xf0003c0,0x3c003c0f,0x3e00,0x787c001f,0x3e00000,0xf80003c,0x3c00,0x1e0,0x1f003e,0x0,0x0,0x1fffc001,0xe7ff0000,0x3ffe000f,
      0xfe78003f,0xfc001fff,0xfe001ffc,0xf0078ffc,0x1ffc00,0x7ff000,0x7800f80,0x1e0000f,0x7f1fc01e,0x3ff0001f,0xfe00079f,0xfc0007ff,
      0x3c003c7f,0xf001fff8,0x1fffff0,0x3c003c0,0xf0000f1e,0xf1f,0x7c1f0,0x1f00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3c00000,0x100000,
      0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7800000,0x1,0xe00f0000,0x1000000,0xf80000,0x40000002,0xf,0x80001f00,0x7e0f8,0x1f07c0,
      0x0,0x0,0x0,0x70,0x38c7003f,0xff000000,0xff8f,0xf8000100,0xffffe,0x7c0f80,0x0,0x0,0x3ffc000,0xf0000020,0x1001f0,0x3c00003c,
      0x1f80,0x0,0x1c3ffc7,0x7c0780,0x0,0x0,0xe3,0xff038000,0xe0,0x38000078,0x78,0x1ff0,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,
      0x7800000,0x1c00,0xe000,0xe00,0xf000,0x78f000,0x3c78000,0x1e3c0000,0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,
      0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,
      0x4000200f,0x3f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801f03e,0x1ffffe,0xf01fe0,0x3fff800,0x1fffc000,0xfffe0007,0xfff0003f,
      0xff8001ff,0xfc003ff3,0xfe0003ff,0xe0007ff8,0x3ffc0,0x1ffe00,0xfff000,0x3ff80001,0xffc0000f,0xfe00007f,0xf000003f,0xf8003c7f,
      0xe0003ffc,0x1ffe0,0xfff00,0x7ff800,0x3ffc000,0x1f80000,0xfff1c03c,0x3c01e0,0x1e00f00,0xf007800,0x781f0001,0xf01e7ff0,0x7c0007c,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,
      0x3c1e003f,0xfffff078,0x30003803,0x80000f00,0x1e0,0x1f00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x3c000f00,0x780001e,0x0,0x7800000f,
      0x78780,0x3c00000,0x3c000000,0x7c00f,0x780f0,0x3c0007,0xe000003f,0x0,0xfe000000,0xfe0000,0x3c0,0x1f000070,0x7c7c003,0xc000f01e,
      0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c1f0000,0x7800001e,0x783cf079,0xe01e03c0,0xf00780,0x1e0f000,0x3c078001,
      0xe03c0000,0xf000,0xf0003c0,0x3c003c07,0x81f03c00,0x7c7c000f,0x87c00000,0xf00003c,0x1e00,0x1e0,0x3e001f,0x0,0x0,0x3fffe001,
      0xefff8000,0x7fff001f,0xff78007f,0xfe001fff,0xfe003ffe,0xf0079ffe,0x1ffc00,0x7ff000,0x7801f00,0x1e0000f,0xffbfe01e,0x7ff8003f,
      0xff0007bf,0xfe000fff,0xbc003cff,0xf803fffc,0x1fffff0,0x3c003c0,0x78001e1e,0xf0f,0x800f80f0,0x1e00ff,0xffe0001e,0xf0,0x780,
      0x0,0x0,0x3c00000,0x380000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1008000,0x7800000,0x3,0xe00f0000,0x3800000,0xf00000,0xe0000007,
      0xf,0x80001f00,0x3e0f8,0x1e07c0,0x0,0x0,0x0,0x70,0x3807007f,0xff800000,0x1ffdf,0xfc000380,0xffffe,0x3e1f00,0x0,0x0,0xfffe000,
      0xf0000030,0x3800f8,0x7c00003c,0xfc0,0x0,0x18780c3,0xf00780,0x80100,0x0,0xc3,0xffc18000,0xf0,0x78000078,0xf0,0xf0,0x0,0x3c003c0,
      0xfffe1c00,0x0,0x0,0x380000f0,0x7800801,0x1c00,0xe000,0x1e00,0xf000,0xf8f800,0x7c7c000,0x3e3e0001,0xf1f0000f,0x8f80007c,0x7c000787,
      0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078001,0xe03c000f,
      0x1e00078,0xf0003c0,0x78001e00,0xe000701f,0x3fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x7800f87c,0x1e007f,0xf07e00,0x7fffc00,0x3fffe001,
      0xffff000f,0xfff8007f,0xffc003ff,0xfe007ff7,0xff0007ff,0xf000fffc,0x7ffe0,0x3fff00,0x1fff800,0x3ff80001,0xffc0000f,0xfe00007f,
      0xf00000ff,0xf8003cff,0xf0007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x1f80001,0xfffb803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,
      0xe01efff8,0x3c00078,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e003f,0xfffff078,0x30001c07,0xf80,0x1e0,0x1e00,0x3c00,0xff800,0x1e0000,0x0,0x0,0x0,0x3c001e00,
      0x3c0001e,0x0,0x7800001e,0x70780,0x3c00000,0x78000000,0x78007,0x800f00f0,0x3e0007,0xe000003f,0x3,0xfe000000,0xff8000,0x7c0,
      0x1e000070,0x783c003,0xc001f01e,0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c3e0000,0x7800001e,0x3838f079,
      0xe01e03c0,0x780780,0x1e0f000,0x1e078001,0xe03c0000,0xf000,0xf0003c0,0x3c007c07,0x81f03c00,0x3ef80007,0x87800000,0x1f00003c,
      0x1e00,0x1e0,0x7c000f,0x80000000,0x0,0x3ffff001,0xffffc000,0xffff003f,0xff7800ff,0xff001fff,0xfe007ffe,0xf007bffe,0x1ffc00,
      0x7ff000,0x7803e00,0x1e0000f,0xffffe01e,0xfff8007f,0xff8007ff,0xff001fff,0xbc003dff,0xf807fffc,0x1fffff0,0x3c003c0,0x78001e0f,
      0x1e07,0xc01f00f0,0x1e00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7c00000,0x7c0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1018000,0x7800000,
      0x3,0xc00f0000,0x7c00000,0x1f00001,0xf000000f,0x80000007,0xc0003e00,0x1e07c,0x3e0780,0x0,0x0,0x0,0x70,0x380700ff,0xff800000,
      0x3ffff,0xfe0007c0,0xffffe,0x1e1e00,0x0,0x780000,0x1fffe000,0xf0000078,0x7c0078,0x7800003c,0xff0,0x0,0x38e0003,0x80f00780,
      0x180300,0x0,0x1c3,0x81e1c000,0x7f,0xf0000078,0x1e0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800c01,0x80001c00,
      0xe000,0x603e00,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x7800078,0x3c000f87,0x8001e000,0x78000,0x3c0000,0x1e00000,
      0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f01,0xf000f81e,
      0x7bc0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007878,0x1e001f,0xf0f800,0x7fffe00,0x3ffff001,0xffff800f,0xfffc007f,0xffe003ff,
      0xff007fff,0xff800fff,0xf001fffe,0xffff0,0x7fff80,0x3fffc00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00001ff,0xfc003dff,0xf000ffff,
      0x7fff8,0x3fffc0,0x1fffe00,0xffff000,0x1f80003,0xffff803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,0xe01ffffc,0x3c00078,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,
      0x3c1e003f,0xfffff078,0x30001e0f,0x300780,0x1e0,0x1e00,0x3c00,0x3dde00,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf800003e,
      0xf0780,0x3dfc000,0x783f8000,0xf8007,0xc01f00f0,0x3e0007,0xe000003f,0x1f,0xfc000000,0x7ff000,0xf80,0x3e007c70,0x783c003,0xc001e03c,
      0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,0x80007800,0x780,0x3c7c0000,0x7800001e,0x3878f078,0xf01e03c0,0x780780,0x1e0f000,0x1e078001,
      0xe03e0000,0xf000,0xf0003c0,0x1e007807,0x83f03c00,0x3ef00007,0xcf800000,0x3e00003c,0xf00,0x1e0,0xf80007,0xc0000000,0x0,0x3e01f801,
      0xfe07e001,0xf80f007e,0x7f801f8,0x1f801fff,0xfe00fc0f,0xf007f83f,0x1ffc00,0x7ff000,0x7807c00,0x1e0000f,0x87e1e01f,0xe0fc00fc,
      0xfc007f8,0x1f803f03,0xfc003df0,0x3807e03c,0x1fffff0,0x3c003c0,0x78003e0f,0x1e03,0xe03e00f8,0x3e00ff,0xffe0001e,0xf0,0x780,
      0x0,0x0,0x7800000,0xfe0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7c00000,0x3,0xc00f0000,0xfe00000,0x3e00003,0xf800001f,
      0xc0000007,0xc0003e00,0x1e03c,0x3c0f80,0x0,0x0,0x0,0x70,0x380700fc,0x7800000,0x7c1fe,0x3e000fe0,0xffffe,0x1f3e00,0x0,0x780000,
      0x3f98e000,0xf000003c,0xfcf8007c,0xf800003c,0x3ffc,0x0,0x31c0001,0x80f00f80,0x380700,0x0,0x183,0x80e0c000,0x3f,0xe0000078,
      0x3c0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x38000078,0xf000e01,0xc003ffe0,0x1fff00,0x7ffc00,0xf000,0xf07800,0x783c000,0x3c1e0001,
      0xe0f0000f,0x7800078,0x3c000f07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,
      0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf801f01e,0xf3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007cf8,
      0x1e000f,0x80f0f000,0x7c03f00,0x3e01f801,0xf00fc00f,0x807e007c,0x3f003e0,0x1f80707f,0x8f801f80,0xf003f03f,0x1f81f8,0xfc0fc0,
      0x7e07e00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00003ff,0xfc003fc1,0xf801f81f,0x800fc0fc,0x7e07e0,0x3f03f00,0x1f81f800,0x1f80007,
      0xe07f003c,0x3c01e0,0x1e00f00,0xf007800,0x780f8003,0xe01fe07e,0x3e000f8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3f,0xfffff078,0x30000ffe,0x1f007c0,0x0,0x1e00,
      0x3c00,0xf9cf80,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf00000fc,0x1e0780,0x3fff800,0x78ffe000,0xf0003,0xe03e00f0,
      0x3e0007,0xe000003f,0x7f,0xe01fffff,0xf00ffc00,0x1f80,0x3c01ff70,0x783c003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,
      0x80007800,0x780,0x3cfc0000,0x7800001e,0x3c78f078,0xf01e03c0,0x780780,0x3e0f000,0x1e078003,0xc01f0000,0xf000,0xf0003c0,0x1e007807,
      0x83f83c00,0x1ff00003,0xcf000000,0x3e00003c,0xf00,0x1e0,0x0,0x0,0x0,0x20007801,0xfc03e003,0xe003007c,0x3f803e0,0x7c0003c,
      0xf807,0xf007e00f,0x3c00,0xf000,0x780f800,0x1e0000f,0x87e1f01f,0x803c00f8,0x7c007f0,0xf803e01,0xfc003f80,0x80f8004,0x3c000,
      0x3c003c0,0x3c003c0f,0x1e03,0xe03e0078,0x3c0000,0x7c0001e,0xf0,0x780,0x0,0x0,0x3ffff800,0x1ff0000,0x0,0x7800000,0x0,0x18,
      0xc0,0x0,0x1818000,0x3e00000,0x3,0xc00f0000,0x1ff00000,0x3e00007,0xfc00003f,0xe0000003,0xc0003c00,0xf03c,0x3c0f00,0x0,0x0,
      0x0,0x70,0x380701f0,0x800000,0x780fc,0x1e001ff0,0x7c,0xf3c00,0x0,0x780000,0x7e182000,0xf000001f,0xfff00ffc,0xffc0003c,0x3cfe,
      0x0,0x31c0001,0x80f01f80,0x780f00,0x0,0x183,0x80e0c000,0xf,0x80000078,0x780,0x38,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x38000078,
      0xf000f01,0xe003ffe0,0x1fff00,0x7ff800,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x78000f8,0x3e000f07,0x8003c000,0x78000,
      0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,
      0x78000f00,0x7c03e01e,0x1e3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78003cf0,0x1e0007,0x80f1e000,0x4000f00,0x20007801,0x3c008,
      0x1e0040,0xf00200,0x780403f,0x7803e00,0x3007c00f,0x803e007c,0x1f003e0,0xf801f00,0x780000,0x3c00000,0x1e000000,0xf00007f0,
      0x3e003f00,0x7801f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e003c,0x3c01e0,0x1e00f00,0xf007800,0x78078003,
      0xc01fc03e,0x1e000f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xf078007c,0x300007fc,0x7e00fe0,0x0,0x1e00,0x3c00,0x3e1c3e0,0x1e0000,0x0,0x0,0x0,0xf0001e00,
      0x3c0001e,0x1,0xf000fff8,0x1e0780,0x3fffe00,0x79fff000,0x1f0001,0xfffc00f0,0x7e0007,0xe000003f,0x3ff,0x801fffff,0xf003ff80,
      0x3f00,0x3c03fff0,0xf01e003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3df80000,0x7800001e,
      0x1c70f078,0x781e03c0,0x780780,0x3c0f000,0x1e078007,0xc01f8000,0xf000,0xf0003c0,0x1e007807,0x83f83c00,0xfe00003,0xff000000,
      0x7c00003c,0x780,0x1e0,0x0,0x0,0x0,0x7c01,0xf801f007,0xc00100f8,0x1f803c0,0x3c0003c,0x1f003,0xf007c00f,0x80003c00,0xf000,
      0x783f000,0x1e0000f,0x3c0f01f,0x3e01f0,0x3e007e0,0x7c07c00,0xfc003f00,0xf0000,0x3c000,0x3c003c0,0x3c003c0f,0x1e01,0xf07c007c,
      0x7c0000,0xfc0001e,0xf0,0x780,0x0,0x0,0x3ffff000,0x3838000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0xff0000,0x3f00000,0x3,0xc00fff00,
      0x38380000,0x7c0000e,0xe000070,0x70000001,0xe0003c00,0xf01e,0x780e00,0x0,0x0,0x0,0x0,0x1e0,0x0,0x780f8,0xf003838,0xfc,0xffc00,
      0x0,0x780000,0x7c180000,0xf000000f,0xffe00fff,0xffc0003c,0x783f,0x80000000,0x6380000,0xc0f83f80,0xf81f00,0x0,0x303,0x80e06000,
      0x0,0x78,0xf00,0x78,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x3800003c,0x3e000f81,0xf003ffe0,0x1fff00,0x1fc000,0xf000,0x1e03c00,
      0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e000f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,
      0x3c000001,0xe0001e00,0x3c0f0f0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3e07c01e,0x1e3c0f0,0x3c0780,0x1e03c00,
      0xf01e000,0x78003ff0,0x1e0007,0x80f1e000,0xf80,0x7c00,0x3e000,0x1f0000,0xf80000,0x7c0001e,0x3c07c00,0x10078007,0x803c003c,
      0x1e001e0,0xf000f00,0x780000,0x3c00000,0x1e000000,0xf00007c0,0x1e003e00,0x7c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,
      0xf,0x801f003c,0x3c01e0,0x1e00f00,0xf007800,0x7807c007,0xc01f801f,0x1f001f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xe078003c,0x300001f0,0x3f801ff0,0x0,
      0x3c00,0x1e00,0x3c1c1e0,0x1e0000,0x0,0x0,0x0,0xf0001e0f,0x3c0001e,0x3,0xe000fff0,0x3c0780,0x3ffff00,0x7bfff800,0x1e0000,0x7ff00078,
      0x7e0007,0xe000003f,0x1ffc,0x1fffff,0xf0007ff0,0x7e00,0x3c07c3f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,
      0x1fffff,0x80007800,0x780,0x3ffc0000,0x7800001e,0x1ef0f078,0x781e03c0,0x780780,0x7c0f000,0x1e07801f,0x800ff000,0xf000,0xf0003c0,
      0xf00f807,0x83b83c00,0xfc00001,0xfe000000,0xf800003c,0x780,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0xc00000f0,0xf80780,0x3c0003c,
      0x1e001,0xf007c007,0x80003c00,0xf000,0x787e000,0x1e0000f,0x3c0f01f,0x1e01e0,0x1e007c0,0x3c07800,0x7c003f00,0xf0000,0x3c000,
      0x3c003c0,0x3e007c07,0x80003c00,0xf8f8003c,0x780000,0xf80001e,0xf0,0x780,0x0,0x0,0x7ffff000,0x601c000,0x3,0xffff0000,0x0,
      0xfff,0xf8007fff,0xc0000000,0x7e003c,0x1fe0000,0xc0003,0xc00fff00,0x601c0000,0xf800018,0x70000c0,0x38000001,0xe0007800,0x701e,
      0x701e00,0x0,0x0,0x0,0x0,0x1e0,0x6,0x700f8,0xf00601c,0xf8,0x7f800,0x0,0x780000,0xf8180000,0xf000000f,0x87c00fff,0xffc0003c,
      0xf01f,0xc0000000,0x6380000,0xc07ff780,0x1f03e03,0xfffffe00,0x303,0x81c06000,0x0,0x1ffff,0xfe001e00,0x180f8,0x0,0x3c003c0,
      0x3ffe1c00,0x3f00000,0x0,0x3800003f,0xfe0007c0,0xf8000000,0x18000000,0xc0000006,0x1f000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,
      0x3c000f0,0x1e001f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f0f0,
      0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f0f801e,0x3c3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,
      0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07c00,0xf0007,0x8078003c,0x3c001e0,0x1e000f00,0x780000,0x3c00000,
      0x1e000000,0xf0000f80,0x1f003e00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0xf,0x3f003c,0x3c01e0,0x1e00f00,0xf007800,
      0x7803c007,0x801f000f,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe078003f,0xb0000000,0xfc003cf0,0x0,0x3c00,0x1e00,0x101c040,0x1e0000,0x0,0x0,0x1,
      0xe0001e1f,0x83c0001e,0x7,0xe000fff0,0x3c0780,0x3c03f80,0x7fc0fc00,0x1e0000,0xfff80078,0xfe0007,0xe000003f,0x7fe0,0x1fffff,
      0xf0000ffc,0xfc00,0x780f81f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3ffc0000,
      0x7800001e,0x1ef0f078,0x3c1e03c0,0x780780,0x1fc0f000,0x1e07ffff,0x7ff00,0xf000,0xf0003c0,0xf00f007,0xc3b87c00,0x7c00001,0xfe000000,
      0xf800003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0x800000f0,0xf80780,0x1e0003c,0x1e001,0xf0078007,0x80003c00,0xf000,0x78fc000,
      0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,0x3c07800,0x7c003e00,0xf0000,0x3c000,0x3c003c0,0x1e007807,0x80003c00,0x7df0003c,0x780000,
      0x1f00001e,0xf0,0x780,0x0,0x0,0x7800000,0xe7ce000,0x3,0xffff0000,0x0,0xfff,0xf8007fff,0xc0000000,0x1f0,0xffe000,0x1c0003,
      0xc00fff00,0xe7ce0000,0xf800039,0xf38001cf,0x9c000000,0xe0007800,0x780e,0x701c00,0x0,0x0,0x0,0x0,0x1e0,0x7,0xf0078,0xf00e7ce,
      0x1f0,0x7f800,0x0,0x780000,0xf0180000,0xf000000e,0x1c0001f,0xe000003c,0xf007,0xe0000000,0x6380000,0xc03fe780,0x3e07c03,0xfffffe00,
      0x303,0xffc06000,0x0,0x1ffff,0xfe003ffe,0x1fff0,0x0,0x3c003c0,0x1ffe1c00,0x3f00000,0x7,0xffc0001f,0xfc0003e0,0x7c000001,0xfc00000f,
      0xe000007f,0x1e000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,
      0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,
      0x783c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07800,
      0xf0003,0xc078001e,0x3c000f0,0x1e000780,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,
      0x7800780,0x3c003c00,0xf,0x7f003c,0x3c01e0,0x1e00f00,0xf007800,0x7803c007,0x801f000f,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe070001f,0xf8000007,
      0xf0007cf8,0x7800000,0x3c00,0x1e00,0x1c000,0x1e0000,0x0,0x0,0x1,0xe0001e1f,0x83c0001e,0xf,0xc000fff8,0x780780,0x2000f80,0x7f803e00,
      0x3e0003,0xfffe007c,0x1fe0000,0x0,0x3ff00,0x0,0x1ff,0x8001f000,0x780f00f0,0x1f00f003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,
      0xfe03c00f,0xf81fffff,0x80007800,0x780,0x3ffe0000,0x7800001e,0xee0f078,0x3c1e03c0,0x7807ff,0xff80f000,0x1e07fffe,0x3ffe0,
      0xf000,0xf0003c0,0xf00f003,0xc7bc7800,0xfc00000,0xfc000001,0xf000003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xe000f80f,0x800001e0,
      0xf80f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x79f8000,0x1e0000f,0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003e00,
      0xf0000,0x3c000,0x3c003c0,0x1e007807,0x81e03c00,0x7df0003e,0xf80000,0x3e00003e,0xf0,0x7c0,0xfc000,0x80000000,0x7800000,0x1e7cf000,
      0x3,0xffff0000,0x0,0x18,0xc0,0x0,0xf80,0x7ffc00,0x380003,0xc00fff01,0xe7cf0000,0x1f000079,0xf3c003cf,0x9e000000,0xe0007000,
      0x380e,0xe01c00,0x0,0x0,0x0,0x0,0x1e0,0x3,0x800f0078,0xf01e7cf,0x3e0,0x3f000,0x0,0x780000,0xf018001f,0xfff8001e,0x1e0000f,
      0xc000003c,0xf003,0xe0000000,0x6380000,0xc00fc780,0x7c0f803,0xfffffe00,0x303,0xfe006000,0x0,0x1ffff,0xfe003ffe,0x1ffe0,0x0,
      0x3c003c0,0xffe1c00,0x3f00000,0x7,0xffc00007,0xf00001f0,0x3e00001f,0xfc0000ff,0xe00007ff,0x3e000,0x3e01e00,0x1f00f000,0xf8078007,
      0xc03c003e,0x1e001e0,0xf001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,
      0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000fc0,
      0x1e0007,0x80f1f000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c0f800,0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,
      0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1e,0xf7803c,0x3c01e0,0x1e00f00,
      0xf007800,0x7803e00f,0x801e000f,0x80f803e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe0f0000f,0xff00001f,0x8000f87c,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,
      0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x1f,0x800000fe,0xf00780,0x7c0,0x7f001e00,0x3c0007,0xe03f003f,0x3fe0000,0x0,0x3fc00,0x0,
      0x7f,0x8001e000,0x781f00f0,0x1e00f003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3f9f0000,0x7800001e,
      0xfe0f078,0x3c1e03c0,0x7807ff,0xff00f000,0x1e07fff8,0xfff8,0xf000,0xf0003c0,0xf81f003,0xc7bc7800,0xfe00000,0x78000003,0xe000003c,
      0x1e0,0x1e0,0x0,0x0,0x0,0x1fffc01,0xe000780f,0x1e0,0x780f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7bf0000,0x1e0000f,
      0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xf8000,0x3c000,0x3c003c0,0x1f00f807,0x81f03c00,0x3fe0001e,0xf00000,0x7c00007c,
      0xf0,0x3e0,0x3ff801,0x80000000,0x7800000,0x3cfcf800,0x3,0xffff0000,0x0,0x18,0xc0,0x0,0x7c00,0x1fff00,0x700003,0xc00f0003,
      0xcfcf8000,0x3e0000f3,0xf3e0079f,0x9f000000,0xf000,0x1000,0x0,0x0,0x0,0x0,0x0,0x1f0,0x1,0xc00f0078,0xf03cfcf,0x800007c0,0x1e000,
      0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x8000003c,0xf001,0xf0000000,0x6380000,0xc0000000,0xf81f003,0xfffffe00,0x303,
      0x87006000,0x0,0x1ffff,0xfe003ffe,0x7f00,0x0,0x3c003c0,0x3fe1c00,0x3f00000,0x7,0xffc00000,0xf8,0x1f0001ff,0xf0000fff,0x80007ffc,
      0xfc000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf001e07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,
      0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3fc001e,0x1e03c0f0,0x3c0780,
      0x1e03c00,0xf01e000,0x78000780,0x1e0007,0x80f0fc00,0x3fff80,0x1fffc00,0xfffe000,0x7fff0003,0xfff8001f,0xffc0001e,0x3c0f000,
      0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,0x3c00000,0x1e000000,0xf0001e00,0xf803c00,0x3c078001,0xe03c000f,0x1e00078,
      0xf0003c0,0x78001e07,0xfffffe1e,0x1e7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801e00f,0x1e0007,0x807803c0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00007,
      0xffc0007e,0xf03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x3f,0x3e,0xf00780,0x3c0,0x7e001e00,
      0x7c000f,0x800f001f,0xffde0000,0x0,0x3e000,0x0,0xf,0x8003e000,0x781e0070,0x1e00f003,0xc001f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,
      0xf81e0007,0x80007800,0x780,0x3f1f0000,0x7800001e,0x7c0f078,0x1e1e03c0,0x7807ff,0xfc00f000,0x1e07fffe,0xffc,0xf000,0xf0003c0,
      0x781e003,0xc71c7800,0x1ff00000,0x78000003,0xe000003c,0x1e0,0x1e0,0x0,0x0,0x0,0xffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,
      0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7f000,0x3c000,
      0x3c003c0,0xf00f007,0xc1f07c00,0x1fc0001f,0x1f00000,0xfc000ff8,0xf0,0x1ff,0xfffe07,0x80000000,0x7800000,0x7ffcfc00,0x0,0xf000000,
      0x0,0x18,0xc0,0x0,0x3e000,0x1ff80,0xe00003,0xc00f0007,0xffcfc000,0x3e0001ff,0xf3f00fff,0x9f800000,0x6000,0x0,0x0,0x7c000,
      0x0,0x0,0x0,0xfe,0x0,0xe00f007f,0xff07ffcf,0xc0000fc0,0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x80000000,0xf800,
      0xf0000000,0x6380000,0xc0000000,0x1f03c000,0x1e00,0x303,0x83806000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xfe1c00,0x3f00000,0x0,
      0x0,0x3c,0xf801fff,0xfff8,0x7ffc0,0x1f8000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf003c07,0x8003c000,0x78000,
      0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,
      0x78000f00,0x1f8001e,0x1e03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e000f,0x80f0ff00,0x1ffff80,0xffffc00,0x7fffe003,
      0xffff001f,0xfff800ff,0xffc007ff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,
      0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x3c7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801f01f,
      0x1e0007,0x807c07c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00000,0xfff003f0,0x1f00f03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x7ff80000,0x3,
      0xc0001e0f,0x3c0001e,0x7e,0x1f,0x1e00780,0x3e0,0x7e000f00,0x78000f,0x7800f,0xff9e0000,0x0,0x3fc00,0x0,0x7f,0x8003c000,0x781e0070,
      0x3e00f803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3e0f8000,0x7800001e,0x7c0f078,0x1e1e03c0,
      0x7807ff,0xf000f000,0x1e07807f,0xfe,0xf000,0xf0003c0,0x781e003,0xc71c7800,0x3ef00000,0x78000007,0xc000003c,0x1e0,0x1e0,0x0,
      0x0,0x0,0x1ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,
      0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7ff80,0x3c000,0x3c003c0,0xf00f003,0xc1f07800,0x1fc0000f,0x1e00000,0xf8000ff0,0xf0,
      0xff,0xffffff,0x80000000,0x3fffc000,0xfff9fe00,0x0,0xf000000,0x0,0x18,0xc0,0x0,0x1f0000,0x1fc0,0x1c00003,0xc00f000f,0xff9fe000,
      0x7c0003ff,0xe7f81fff,0x3fc00000,0x0,0x0,0x0,0xfe000,0x1ffffc0f,0xfffffc00,0x0,0xff,0xf0000000,0x700f007f,0xff0fff9f,0xe0000f80,
      0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00fff,0xffc00000,0xf800,0xf0000000,0x6380000,0xc0ffff80,0x3e078000,0x1e00,0x7ff80303,
      0x83c06000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,0x0,0x7f,0xff00001e,0x7c1fff0,0xfff80,0x7ffc00,0x3f0000,0x7c01f00,
      0x3e00f801,0xf007c00f,0x803e007c,0x1f003e0,0xf803c07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
      0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f8001e,0x3c03c0f0,0x3c0780,0x1e03c00,0xf01e000,
      0x78000780,0x1e001f,0xf07f80,0x3ffff80,0x1ffffc00,0xffffe007,0xffff003f,0xfff801ff,0xffc03fff,0xffc0f000,0x1fffff,0xc0fffffe,
      0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,
      0xfffffe1e,0x787803c,0x3c01e0,0x1e00f00,0xf007800,0x7800f01e,0x1e0007,0x803c0780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x3ff80fc0,0x7fc1e01f,
      0x7800000,0x3c00,0x1e00,0x0,0x7fffff80,0x0,0x7ff80000,0x7,0x80001e00,0x3c0001e,0xfc,0xf,0x1e00780,0x1e0,0x7c000f00,0x78000f,
      0x78007,0xff1e0000,0x0,0x3ff00,0x0,0x1ff,0x8003c000,0x781e0070,0x3c007803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,
      0x80007800,0x780,0x3c07c000,0x7800001e,0x7c0f078,0xf1e03c0,0x780780,0xf000,0x1e07801f,0x3e,0xf000,0xf0003c0,0x781e003,0xcf1c7800,
      0x3cf80000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,0x0,0x0,0x3ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,
      0x80003c00,0xf000,0x7ff8000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3fff0,0x3c000,0x3c003c0,0xf81f003,
      0xc3b87800,0xf80000f,0x1e00001,0xf0000ff0,0xf0,0xff,0xf03fff,0x80000000,0x3fff8001,0xfff1ff00,0x0,0xf000000,0x0,0x18,0xc0,
      0x0,0x380000,0x7c0,0x3c00003,0xc00f001f,0xff1ff000,0xf80007ff,0xc7fc3ffe,0x3fe00000,0x0,0x0,0x0,0x1ff000,0x7ffffe1f,0xffffff00,
      0x0,0x7f,0xfe000000,0x780f007f,0xff1fff1f,0xf0001f00,0x1e000,0x0,0x780001,0xe0180000,0xf000001c,0xe00fff,0xffc00000,0x7c00,
      0xf0000000,0x31c0001,0x80ffff80,0x3e078000,0x1e00,0x7ff80183,0x81c0c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,
      0x0,0x7f,0xff00001e,0x7c7ff03,0xc03ff8fe,0x1ffc0f0,0x7e0000,0x7800f00,0x3c007801,0xe003c00f,0x1e0078,0xf003c0,0x7803c07,0x8003c000,
      0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,
      0xf0001e0,0x78000f00,0x3fc001e,0x7803c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e007f,0xf03fe0,0x7ffff80,0x3ffffc01,
      0xffffe00f,0xffff007f,0xfff803ff,0xffc07fff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,
      0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x707803c,0x3c01e0,0x1e00f00,0xf007800,
      0x7800f01e,0x1e0007,0x803c0780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x30f81f00,0xffe1e00f,0x87800000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,
      0x7,0x80001e00,0x3c0001e,0x1f8,0x7,0x83c00780,0x1e0,0x7c000f00,0xf8001e,0x3c001,0xfc1e0000,0x0,0x7fe0,0x0,0xffc,0x3c000,0x781e0070,
      0x3ffff803,0xc000783c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x380f078,0xf1e03c0,
      0x780780,0xf000,0x1e07800f,0x8000001e,0xf000,0xf0003c0,0x3c3c003,0xcf1e7800,0x7c780000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,
      0x0,0x0,0x7f003c01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7f7c000,0x1e0000f,0x3c0f01e,
      0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfff8,0x3c000,0x3c003c0,0x781e003,0xc3b87800,0x1fc00007,0x83e00003,0xe0000ff8,0xf0,
      0x1ff,0xc007fe,0x0,0x7fff8001,0xffe3ff00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x3c0,0x7800003,0xc00f001f,0xfe3ff000,0xf80007ff,
      0x8ffc3ffc,0x7fe00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x1f,0xff000000,0x3c0f007f,0xff1ffe3f,0xf0003e00,0x1e000,0x0,0x780001,
      0xe0180000,0xf000001e,0x1e00fff,0xffc00000,0x3f00,0xf0000000,0x31c0001,0x80ffff80,0x1f03c000,0x1e00,0x7ff80183,0x81c0c000,
      0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x7f,0xff00003c,0xf87f007,0xc03f83ff,0x81fc01f0,0x7c0000,0x7ffff00,0x3ffff801,
      0xffffc00f,0xfffe007f,0xfff003ff,0xff807fff,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
      0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf003c0f0,0x3c0780,0x1e03c00,0xf01e000,
      0x78000780,0x1ffffe,0xf00ff0,0xfe00780,0x7f003c03,0xf801e01f,0xc00f00fe,0x7807f0,0x3c0ffff,0xffc0f000,0x1fffff,0xc0fffffe,
      0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,
      0x1e,0xf07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783e,0x1e0007,0x801e0f80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x307c0801,0xe1f1e00f,0x87000000,
      0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,0xf,0x1e00,0x3c0001e,0x3f0,0x7,0x83fffffc,0x1e0,0x7c000f00,0xf0001e,0x3c000,0x3e0000,
      0x0,0x1ffc,0x1fffff,0xf0007ff0,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x3c000,0x781e0007,0x80007800,
      0x780,0x3c03e000,0x7800001e,0xf078,0x79e03c0,0x780780,0xf000,0x1e078007,0x8000000f,0xf000,0xf0003c0,0x3c3c001,0xee0ef000,
      0xf87c0000,0x7800001f,0x3c,0x78,0x1e0,0x0,0x0,0x0,0x7c003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00,
      0xf000,0x7e3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x1ffc,0x3c000,0x3c003c0,0x781e003,0xe3b8f800,
      0x1fc00007,0x83c00007,0xc00000fc,0xf0,0x3e0,0x8001f8,0x0,0x7800000,0xffc7fe00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,
      0xf000003,0xc00f000f,0xfc7fe001,0xf00003ff,0x1ff81ff8,0xffc00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x3,0xff800000,0x1e0f0078,
      0xffc7f,0xe0007c00,0x1e000,0x0,0x780001,0xe0180000,0xf000000e,0x1c00007,0x80000000,0x1f81,0xe0000000,0x38e0003,0x80000000,
      0xf81f000,0x1e00,0x7ff801c3,0x80e1c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf8,0x1f070007,0xc03803ff,0xc1c001f0,
      0xf80000,0xfffff00,0x7ffff803,0xffffc01f,0xfffe00ff,0xfff007ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,
      0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f00f,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,0xf003c0f0,
      0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1ffffc,0xf003f8,0xf800780,0x7c003c03,0xe001e01f,0xf00f8,0x7807c0,0x3c0fc1e,0xf000,
      0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,
      0xf0003c0,0x78001e00,0x1e,0x1e07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783c,0x1e0007,0x801e0f00,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xffff8000,0x303c0001,
      0xc071e007,0xcf000000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0xf,0xf00,0x780001e,0x7e0,0x7,0x83fffffc,0x1e0,0x7c000f00,0x1f0001e,
      0x3c000,0x3c0000,0x0,0x3ff,0x801fffff,0xf003ff80,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,
      0x80007800,0x780,0x3c01f000,0x7800001e,0xf078,0x79e03c0,0xf00780,0xf000,0x3e078007,0xc000000f,0xf000,0xf0003c0,0x3c3c001,
      0xee0ef000,0xf03e0000,0x7800003e,0x3c,0x78,0x1e0,0x0,0x0,0x0,0xf8003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,
      0x80003c00,0xf000,0x7c3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfc,0x3c000,0x3c003c0,0x3c3e001,0xe7b8f000,
      0x3fe00007,0xc7c0000f,0xc000003e,0xf0,0x7c0,0x0,0x0,0x7c00000,0x7fcffc00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,0x1e000003,
      0xc00f0007,0xfcffc003,0xe00001ff,0x3ff00ff9,0xff800000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x1f800000,0xf0f0078,0x7fcff,
      0xc000fc00,0x1e000,0x0,0x780001,0xe0180000,0xf000000f,0x87c00007,0x80000000,0xfe3,0xe0000000,0x18780c3,0x0,0x7c0f800,0x1e00,
      0xc3,0x80e18000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x1f0,0x3e00000f,0xc0000303,0xe00003f0,0xf00000,0xfffff80,
      0x7ffffc03,0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,
      0x3c000001,0xe0001e00,0x780f00f,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1f0f801f,0xe00780f0,0x3c0780,0x1e03c00,
      0xf01e000,0x78000780,0x1ffff8,0xf000f8,0x1f000780,0xf8003c07,0xc001e03e,0xf01f0,0x780f80,0x3c1f01e,0xf000,0x1e0000,0xf00000,
      0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,
      0x1e,0x3c07803c,0x3c01e0,0x1e00f00,0xf007800,0x78007c7c,0x1e0007,0x801f1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c00000,0x303c0003,0x8039e003,0xef000000,
      0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0xfc0,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,
      0x0,0x7f,0xe01fffff,0xf00ffc00,0x3c000,0x781f00f0,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,0x80007800,
      0x780,0x3c01f000,0x7800001e,0xf078,0x7de01e0,0xf00780,0x7800,0x3c078003,0xc000000f,0xf000,0xf0003c0,0x3e7c001,0xee0ef001,
      0xf01e0000,0x7800003e,0x3c,0x3c,0x1e0,0x0,0x0,0x0,0xf0003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00,
      0xf000,0x781f000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0x7df00003,
      0xc780000f,0x8000003e,0xf0,0x780,0x0,0x0,0x3c00000,0x3fcff800,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x1f00fc,0x1e0,0x1e000001,
      0xe00f0003,0xfcff8003,0xe00000ff,0x3fe007f9,0xff000000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x7c00000,0xf0f0078,0x3fcff,0x8000f800,
      0x1e000,0x0,0x780001,0xe0180000,0xf000001f,0xffe00007,0x8000003c,0x7ff,0xc0000000,0x1c3ffc7,0x0,0x3e07c00,0x1e00,0xe3,0x80738000,
      0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x3e0,0x7c00001d,0xc0000001,0xe0000770,0x1f00000,0xfffff80,0x7ffffc03,
      0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
      0xe0001e00,0x780f00f,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0x3e07c01f,0xc00780f0,0x3c0780,0x1e03c00,0xf01e000,
      0x78000780,0x1fffc0,0xf0007c,0x1e000780,0xf0003c07,0x8001e03c,0xf01e0,0x780f00,0x3c1e01e,0xf000,0x1e0000,0xf00000,0x7800000,
      0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1e,0x7807803c,
      0x3c01e0,0x1e00f00,0xf007800,0x78003c78,0x1e0007,0x800f1e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x83c00000,0x303c0003,0x8039e001,0xee000000,0x1e00,0x3c00,
      0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0x1f80,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,0x0,0x1f,0xfc1fffff,
      0xf07ff000,0x0,0x780f00f0,0x78003c03,0xc000781e,0x1e0,0xf803c0,0x1e00,0x1e000,0x781e0007,0x80007800,0x780,0x3c00f800,0x7800001e,
      0xf078,0x3de01e0,0xf00780,0x7800,0x3c078003,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfe0ff003,0xe01f0000,0x7800007c,0x3c,0x3c,
      0x1e0,0x0,0x0,0x0,0xf0007c01,0xe000f80f,0x800001e0,0xf80f00,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x780f800,0x1e0000f,
      0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003c00,0x1e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0xf8f80003,0xe780001f,0x1e,
      0xf0,0x780,0x0,0x0,0x3c00000,0x1ffff000,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x3bc1de,0x1e0,0xf000001,0xe00f0001,0xffff0007,0xc000007f,
      0xffc003ff,0xfe000000,0x0,0x0,0x0,0xfe000,0x0,0x0,0x0,0x0,0x3c00000,0x1e0f0078,0x1ffff,0x1f000,0x1e000,0x0,0x780000,0xf0180000,
      0xf000001f,0xfff00007,0x8000003c,0x1ff,0x80000000,0xe0ff0e,0x0,0x1f03e00,0x1e00,0x70,0x70000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,
      0xe1c00,0x0,0x0,0x0,0x7c0,0xf8000019,0xc0000000,0xe0000670,0x1e00000,0xf000780,0x78003c03,0xc001e01e,0xf00f0,0x780780,0x3c0f807,
      0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf80f007,0xbc03c001,0xe01e000f,
      0xf00078,0x78003c0,0x3c001e00,0x7c03e00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,
      0xf0007c07,0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0xf800,0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,
      0xf0001e00,0x7803c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1f8001f,0xf00f803c,0x3c01e0,0x1e00f00,0xf007800,
      0x78003e78,0x1e000f,0x800f9e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x3c00000,0x303c0003,0x8039f001,0xfe000000,0x1e00,0x3c00,0x0,0x1e0000,0x0,0x0,0x3c,0xf00,
      0x780001e,0x3f00,0x7,0x80000780,0x3e0,0x3e000f00,0x3c0001e,0x3c000,0x7c0000,0x0,0x3,0xfe000000,0xff8000,0x0,0x3c0f81f0,0xf0001e03,
      0xc000780f,0x1e0,0xf003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x780,0x3c007c00,0x7800001e,0xf078,0x3de01e0,0xf00780,0x7800,
      0x3c078001,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfc07f003,0xe00f0000,0x78000078,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01,
      0xf000f007,0x800000f0,0xf80780,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,
      0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78001,0xe71df000,0xf8f80001,0xef80003e,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,
      0xfffe000,0x0,0x3e000000,0x0,0x18,0x7fff,0xc0000000,0x60c306,0x1e0,0x7800001,0xe00f0000,0xfffe0007,0x8000003f,0xff8001ff,
      0xfc000000,0x0,0x0,0x0,0x7c000,0x0,0x0,0x0,0x0,0x3c00000,0x3c0f0078,0xfffe,0x3e000,0x1e000,0x0,0x780000,0xf0180000,0xf000003c,
      0xfcf80007,0x8000003c,0x7f,0x0,0x70001c,0x0,0xf81f00,0x0,0x38,0xe0000,0x0,0x0,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf81,
      0xf0000039,0xc0000000,0xe0000e70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,0x8000f000,0x78000,
      0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f007,0xbc03c001,0xe01e000f,0xf00078,0x78003c0,
      0x3c001e00,0xf801f00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,0x8003e03c,
      0x1f01e0,0xf80f00,0x7c1e01e,0x7800,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,
      0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xe00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef8,0x1f000f,
      0x7be00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0xf,0x3c00000,0x307c0003,0x8038f000,0xfc000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e00003c,0x780,0xf00001e,
      0x7e00,0xf,0x80000780,0x3c0,0x3e001e00,0x3c0001f,0x7c000,0x780007,0xe000003f,0x0,0xfe000000,0xfe0000,0x0,0x3c07c3f0,0xf0001e03,
      0xc000f80f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x4000f80,0x3c003c00,0x7800001e,0xf078,0x1fe01f0,0x1f00780,
      0x7c00,0x7c078001,0xf000001f,0xf000,0xf0003c0,0x1e78001,0xfc07f007,0xc00f8000,0x780000f8,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01,
      0xf000f007,0xc00000f0,0xf80780,0x3c,0x1f003,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,
      0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78000,0xfe0fe001,0xf07c0001,0xef00007c,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,
      0x7cfc000,0xfc00000,0x3c00000f,0xc3f00000,0x18,0x7fff,0xc0000000,0x406303,0x3e0,0x3c00001,0xf00f0000,0x7cfc000f,0x8000001f,
      0x3f0000f9,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x780700f8,0x7cfc,0x7c000,0x1e000,0x0,0x780000,0xf8180000,
      0xf0000070,0x3c0007,0x8000003c,0x3f,0x80000000,0x3c0078,0x0,0x780f00,0x0,0x1e,0x3c0000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,0xe1c00,
      0x0,0x0,0x0,0xf01,0xe0000071,0xc0000000,0xe0001c70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,
      0x8000f800,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00f003,0xfc03e003,0xe01f001f,
      0xf800f8,0x7c007c0,0x3e003e01,0xf000f80f,0xf00f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,
      0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0x7c00,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,
      0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xc00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef0,
      0x1f000f,0x7bc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x780000,0xf,0x3800040,0x30780003,0x8038f800,0x78000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078,
      0x780,0x1f00001e,0xfc00,0x20001f,0x780,0x80007c0,0x1f001e00,0x7c0000f,0x78000,0xf80007,0xe000003f,0x0,0x1e000000,0xf00000,
      0x3c000,0x3c03fff0,0xf0001e03,0xc001f007,0x800101e0,0x7e003c0,0x1e00,0x7800,0x781e0007,0x80007800,0x6000f00,0x3c003e00,0x7800001e,
      0xf078,0x1fe00f0,0x1e00780,0x3c00,0x78078000,0xf020001e,0xf000,0x7800780,0xff0001,0xfc07f00f,0x8007c000,0x780001f0,0x3c,0xf,
      0x1e0,0x0,0x0,0x0,0xf800fc01,0xf801f007,0xc00100f8,0x1f807c0,0x40003c,0xf807,0xf0078007,0x80003c00,0xf000,0x7803e00,0x1f0000f,
      0x3c0f01e,0x1e01f0,0x3e007e0,0x7c07c00,0xfc003c00,0x1e,0x3e000,0x3e007c0,0x1ff8000,0xfe0fe003,0xe03e0001,0xff0000fc,0x1e,
      0xf0,0x780,0x0,0x0,0x1f00080,0x3cf8000,0xfc00000,0x3c00001f,0x83f00000,0x18,0xc0,0x0,0xc06203,0x40003c0,0x1c00000,0xf80f0000,
      0x3cf8001f,0xf,0x3e000079,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x700780fc,0x3cf8,0xfc000,0x1e000,0x0,0x780000,
      0x7c180000,0xf0000020,0x100007,0x8000003c,0xf,0x80000000,0x1f01f0,0x0,0x380700,0x0,0xf,0x80f80000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,
      0xe1c00,0x0,0x0,0x0,0xe01,0xc0000071,0xc0000001,0xc0001c70,0x1e00040,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,
      0x80007800,0x10078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00f003,0xfc01e003,0xc00f001e,
      0x7800f0,0x3c00780,0x1e003c00,0xe000700f,0x800f0078,0x7803c0,0x3c01e00,0x1e00f000,0xf0000780,0x1e0000,0xf0003c,0x1f001f80,
      0xf800fc07,0xc007e03e,0x3f01f0,0x1f80f80,0xfc1e01f,0x7c00,0x100f8000,0x807c0004,0x3e00020,0x1f000100,0x780000,0x3c00000,0x1e000000,
      0xf0000f80,0x1f003c00,0x3c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,0x1f8000f,0x801f003e,0x7c01f0,0x3e00f80,0x1f007c00,
      0xf8001ff0,0x1f801f,0x7fc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0xf,0x7800078,0x31f80001,0xc070fc00,0xfc000000,0x1e00,0x7c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078,
      0x7c0,0x1f00001e,0x1f000,0x38003f,0x780,0xe000f80,0x1f803e00,0x780000f,0x800f8000,0x1f00007,0xe000003f,0x0,0x2000000,0x800000,
      0x3c000,0x3e01ff71,0xf0001f03,0xc007f007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x781e0007,0x80007800,0x7801f00,0x3c001f00,0x7800001e,
      0xf078,0xfe00f8,0x3e00780,0x3e00,0xf8078000,0xf838003e,0xf000,0x7c00f80,0xff0000,0xfc07e00f,0x8003c000,0x780001e0,0x3c,0xf,
      0x1e0,0x0,0x0,0x0,0xf801fc01,0xfc03e003,0xe003007c,0x3f803e0,0x1c0003c,0xfc0f,0xf0078007,0x80003c00,0xf000,0x7801f00,0xf8000f,
      0x3c0f01e,0x1e00f8,0x7c007f0,0xf803e01,0xfc003c00,0x8003e,0x1f000,0x1e00fc0,0xff0000,0xfe0fe007,0xc01f0000,0xfe0000f8,0x1e,
      0xf0,0x780,0x0,0x0,0xf80180,0x1cf0000,0x1f800000,0x3c00001f,0x83e00000,0x18,0xc0,0x0,0xc06203,0x70007c0,0xe00000,0x7e0f0000,
      0x1cf0001e,0x7,0x3c000039,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100,0x7c00000,0xe00780fc,0x2001cf0,0xf8000,0x1e000,0x0,
      0x780000,0x7e182000,0xf0000000,0x7,0x8000003c,0x7,0xc0000000,0x7ffc0,0x0,0x180300,0x0,0x3,0xffe00000,0x0,0x0,0x0,0x0,0x0,
      0x3f00fc0,0xe1c00,0x0,0x0,0x0,0xc01,0x800000e1,0xc0000003,0xc0003870,0x1f001c0,0x3e0003e1,0xf0001f0f,0x8000f87c,0x7c3e0,0x3e1f00,
      0x1f1e007,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e03,0xfc00f001,0xfc01f007,
      0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x4000201f,0xc01f007c,0xf803e0,0x7c01f00,0x3e00f801,0xf0000780,0x1e0000,0xf0007c,
      0x1f003f80,0xf801fc07,0xc00fe03e,0x7f01f0,0x3f80f80,0x1fc1f03f,0x803e00,0x3007c003,0x803e001c,0x1f000e0,0xf800700,0x780000,
      0x3c00000,0x1e000000,0xf00007c0,0x3e003c00,0x3c01f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e001e,0xfc00f0,
      0x7e00780,0x3f003c01,0xf8000fe0,0x1fc03e,0x3f800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x780007f,0xfff00001,0xe0f07f03,0xfe000000,0xf00,0x7800,0x0,
      0x1e0000,0xfc0000,0x0,0x7e0000f0,0x3f0,0x7e000fff,0xfc03ffff,0xf83f00fe,0x780,0xfc03f80,0xfc0fc00,0xf800007,0xe03f0018,0x7e00007,
      0xe000003f,0x0,0x0,0x0,0x3c000,0x1e007c71,0xe0000f03,0xffffe003,0xf01f01ff,0xff8003ff,0xffe01e00,0x3f01,0xf81e0007,0x803ffff0,
      0x7e03f00,0x3c000f00,0x7ffffe1e,0xf078,0xfe007e,0xfc00780,0x1f83,0xf0078000,0x783f00fe,0xf000,0x3f03f00,0xff0000,0xfc07e01f,
      0x3e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7e07fc01,0xfe07e001,0xf80f007e,0x7f801f8,0xfc0003c,0x7ffe,0xf0078007,
      0x807ffffe,0xf000,0x7801f00,0xfff00f,0x3c0f01e,0x1e00fc,0xfc007f8,0x1f803f03,0xfc003c00,0xf80fc,0x1fff0,0x1f83fc0,0xff0000,
      0xfc07e007,0xc01f0000,0xfe0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfe0780,0xfe0000,0x1f000000,0x3c00001f,0x7c00e03,0x81c00018,
      0xc0,0x0,0x406203,0x7e01fc0,0x700000,0x7fffff80,0xfe0003f,0xffffc003,0xf800001f,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f0,
      0x1f800001,0xc007c1fe,0x6000fe0,0x1ffffe,0x1e000,0x0,0x780000,0x3f98e03f,0xffff8000,0x7,0x8000003c,0x7,0xc0000000,0xfe00,
      0x0,0x80100,0x0,0x0,0x7f000000,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3f83fe8,0xe1c00,0x0,0x0,0x0,0x801,0xc1,0xc0000007,0x80003070,
      0xfc0fc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc03f01,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,
      0xffff001f,0xfff800ff,0xffc01fff,0xf800f001,0xfc00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,0x1f,0xf07e003f,0x3f001f8,
      0x1f800fc0,0xfc007e07,0xe0000780,0x1e0000,0xf301f8,0xfc0ff80,0x7e07fc03,0xf03fe01f,0x81ff00fc,0xff807e0,0x7fc0f87f,0x81801f80,
      0xf003f01f,0x801f80fc,0xfc07e0,0x7e03f00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff807e0,0x7e003c00,0x3c01f81f,0x800fc0fc,0x7e07e0,
      0x3f03f00,0x1f81f800,0x1f8000f,0xe07e001f,0x83fc00fc,0x1fe007e0,0xff003f07,0xf8000fe0,0x1fe07e,0x3f800,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x780007f,
      0xffe00000,0xffe03fff,0xdf000000,0xf00,0x7800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0x1ff,0xfc000fff,0xfc03ffff,0xf83ffffc,0x780,
      0xfffff00,0x7fff800,0xf000007,0xffff001f,0xffe00007,0xe000003f,0x0,0x0,0x0,0x3c000,0x1e000001,0xe0000f03,0xffffc001,0xffff01ff,
      0xff0003ff,0xffe01e00,0x1fff,0xf81e0007,0x803ffff0,0x7fffe00,0x3c000f80,0x7ffffe1e,0xf078,0xfe003f,0xff800780,0xfff,0xf0078000,
      0x7c3ffffc,0xf000,0x3ffff00,0xff0000,0xf803e01e,0x1e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7fffbc01,0xffffc000,
      0xffff003f,0xfff800ff,0xffc0003c,0x3ffe,0xf0078007,0x807ffffe,0xf000,0x7800f80,0x7ff00f,0x3c0f01e,0x1e007f,0xff8007ff,0xff001fff,
      0xbc003c00,0xffffc,0x1fff0,0x1fffbc0,0xff0000,0x7c07c00f,0x800f8000,0x7e0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7fff80,0x7c0000,
      0x1f000000,0x3c00001e,0x7c00f07,0xc1e00018,0xc0,0x0,0x60e303,0x7ffff80,0x380000,0x3fffff80,0x7c0003f,0xffffc001,0xf000000f,
      0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff800003,0x8003ffff,0xfe0007c0,0x1ffffe,0x1e000,0x0,0x780000,0x1fffe03f,0xffff8000,
      0x7,0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3fffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x1c1,
      0xc000000f,0x7070,0x7fffc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,
      0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000f001,0xfc007fff,0x3fff8,0x1fffc0,0xfffe00,0x7fff000,0x3b,0xfffc003f,
      0xfff001ff,0xff800fff,0xfc007fff,0xe0000780,0x1e0000,0xf3fff8,0xffff780,0x7fffbc03,0xfffde01f,0xffef00ff,0xff7807ff,0xfbc0ffff,
      0xff800fff,0xf001ffff,0x800ffffc,0x7fffe0,0x3ffff00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff803ff,0xfc003c00,0x3c00ffff,0x7fff8,
      0x3fffc0,0x1fffe00,0xffff000,0x1f,0xfffc001f,0xffbc00ff,0xfde007ff,0xef003fff,0x780007e0,0x1ffffc,0x1f800,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x700003f,
      0xffc00000,0x7fc01fff,0x9f800000,0xf80,0xf800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0xff,0xf8000fff,0xfc03ffff,0xf83ffff8,0x780,
      0xffffe00,0x7fff000,0xf000003,0xfffe001f,0xffc00007,0xe000003f,0x0,0x0,0x0,0x3c000,0xf000003,0xe0000f83,0xffff0000,0xffff01ff,
      0xfc0003ff,0xffe01e00,0xfff,0xf01e0007,0x803ffff0,0x7fffc00,0x3c0007c0,0x7ffffe1e,0xf078,0x7e003f,0xff000780,0x7ff,0xe0078000,
      0x3c3ffff8,0xf000,0x1fffe00,0x7e0000,0xf803e03e,0x1f000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x3fff3c01,0xefff8000,
      0x7ffe001f,0xff78007f,0xff80003c,0x1ffc,0xf0078007,0x807ffffe,0xf000,0x78007c0,0x3ff00f,0x3c0f01e,0x1e003f,0xff0007bf,0xfe000fff,
      0xbc003c00,0xffff8,0xfff0,0xfff3c0,0x7e0000,0x7c07c01f,0x7c000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3fff80,0x380000,
      0x3e000000,0x7c00003e,0x7801f07,0xc1e00018,0xc0,0x0,0x39c1ce,0x7ffff00,0x1c0000,0xfffff80,0x380003f,0xffffc000,0xe0000007,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff000007,0x1ffcf,0xfe000380,0x1ffffe,0x1e000,0x0,0x780000,0xfffe03f,0xffff8000,0x7,
      0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x381,
      0xc000001e,0xe070,0x7fff80,0x7c0001f3,0xe0000f9f,0x7cf8,0x3e7c0,0x1f3e00,0xfbe007,0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,
      0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000f000,0xfc007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x79,0xfff8001f,
      0xffe000ff,0xff0007ff,0xf8003fff,0xc0000780,0x1e0000,0xf3fff0,0x7ffe780,0x3fff3c01,0xfff9e00f,0xffcf007f,0xfe7803ff,0xf3c07ff3,
      0xff8007ff,0xe000ffff,0x7fff8,0x3fffc0,0x1fffe00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff801ff,0xf8003c00,0x3c007ffe,0x3fff0,
      0x1fff80,0xfffc00,0x7ffe000,0x1d,0xfff8000f,0xff3c007f,0xf9e003ff,0xcf001ffe,0x780007c0,0x1efff8,0x1f000,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0xf000003,
      0xfe000000,0x1f000fff,0xfc00000,0x780,0xf000,0x0,0x0,0xf80000,0x0,0x7e0001e0,0x7f,0xf0000fff,0xfc03ffff,0xf81ffff0,0x780,
      0x7fff800,0x1ffe000,0x1f000000,0xfff8001f,0xff000007,0xe000003e,0x0,0x0,0x0,0x3c000,0xf800003,0xc0000783,0xfff80000,0x3ffe01ff,
      0xe00003ff,0xffe01e00,0x7ff,0xc01e0007,0x803ffff0,0x3fff800,0x3c0003c0,0x7ffffe1e,0xf078,0x7e000f,0xfe000780,0x3ff,0xc0078000,
      0x3e1fffe0,0xf000,0x7ff800,0x7e0000,0xf803e07c,0xf800,0x780003ff,0xfffc003c,0x3,0xc00001e0,0x0,0x0,0x0,0xffe3c01,0xe7ff0000,
      0x3ffc000f,0xfe78003f,0xfe00003c,0x7f0,0xf0078007,0x807ffffe,0xf000,0x78003e0,0xff00f,0x3c0f01e,0x1e001f,0xfe00079f,0xfc0007ff,
      0x3c003c00,0x7ffe0,0x1ff0,0x7fe3c0,0x7e0000,0x7c07c03e,0x3e000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfff00,0x100000,
      0x3e000000,0x7800003c,0xf800f07,0xc1e00018,0xc0,0x0,0x1f80fc,0x3fffc00,0xc0000,0x3ffff80,0x100003f,0xffffc000,0x40000002,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0xfc000006,0xff87,0xfc000100,0x1ffffe,0x1e000,0x0,0x780000,0x3ffc03f,0xffff8000,0x7,
      0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dff9f8,0xe1c00,0x0,0x0,0x0,0x0,0x3ff,
      0xf800003c,0xfffe,0x1ffe00,0x780000f3,0xc000079e,0x3cf0,0x1e780,0xf3c00,0x7bc007,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,
      0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,0xf000,0xfc001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x70,0xfff00007,
      0xff80003f,0xfc0001ff,0xe0000fff,0x780,0x1e0000,0xf3ffe0,0x1ffc780,0xffe3c00,0x7ff1e003,0xff8f001f,0xfc7800ff,0xe3c03fe1,
      0xff0003ff,0xc0007ffc,0x3ffe0,0x1fff00,0xfff800,0xfffffc07,0xffffe03f,0xffff01ff,0xfff800ff,0xf0003c00,0x3c003ffc,0x1ffe0,
      0xfff00,0x7ff800,0x3ffc000,0x38,0xfff00007,0xfe3c003f,0xf1e001ff,0x8f000ffc,0x780007c0,0x1e7ff0,0x1f000,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,
      0x1fc,0x0,0x780,0xf000,0x0,0x0,0x1f80000,0x0,0x1e0,0x1f,0xc0000000,0x0,0x1ff80,0x0,0xffc000,0x7f8000,0x0,0x3fe00007,0xfc000000,
      0x7e,0x0,0x0,0x0,0x0,0x7c00000,0x0,0x0,0xff00000,0x0,0x0,0xfe,0x0,0x0,0x3fc000,0x0,0x0,0x0,0x3,0xf8000000,0xff,0xc0000000,
      0x1ff00,0x0,0x1fe000,0x0,0x0,0x0,0x0,0x3c,0x3,0xc00001e0,0x0,0x0,0x0,0x3f80000,0x1fc0000,0x7f00003,0xf8000007,0xf0000000,
      0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x7,0xf8000787,0xf00001fc,0x3c000000,0x7f80,0x0,0x1f8000,0x0,0x0,0x0,0x7c000000,0x1e,
      0xf0,0x780,0x0,0x0,0x3fc00,0x0,0x3c000000,0x7800003c,0xf000601,0xc00018,0xc0,0x0,0x0,0x3fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xf0000000,0x7e03,0xf0000000,0x0,0x0,0x0,0x0,0xfe0000,0x0,0x0,0x3c,0x2007,0x80000000,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c7e0f0,0xe1c00,0x0,0x3800000,0x0,0x0,0x3ff,0xf8000078,0xfffe,0x7f800,0x0,0x0,0x0,0x0,
      0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,0x7f0000,0x70,0x3fc00001,0xfe00000f,0xf000007f,
      0x800003fc,0x0,0x0,0xff00,0x7f0000,0x3f80000,0x1fc00000,0xfe000007,0xf000003f,0x80001f80,0xfc00007f,0xfe0,0x7f00,0x3f800,
      0x1fc000,0x0,0x0,0x0,0x3f,0xc0000000,0xff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x78,0x3fc00001,0xf800000f,0xc000007e,0x3f0,0x7c0,
      0x1e1fc0,0x1f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x3c0,0x1e000,0x0,0x0,0x1f00000,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0x3e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xe0000000,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x3c,0x1,0xe00001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,
      0x0,0x0,0x0,0x0,0x0,0x0,0x78000000,0x1e,0xf0,0x780,0x0,0x0,0x0,0x0,0x3c000000,0x78000078,0xf000000,0x18,0xc0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3c0f,0x80000000,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0x1800000,0x0,0x0,0x3ff,0xf80000f0,0xfffe,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x0,0x780,0x1e0000,0x1e000,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,
      0x0,0x0,0x3c0,0x1e000,0x0,0x0,0x1f00000,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0x1f80000,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x1,0xe00001e0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe0000000,0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf8000000,
      0x1f,0xf0,0xf80,0x0,0x0,0x0,0x0,0x78000000,0xf8000078,0x1e000000,0x8,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3fff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x3c00000,0xe1c00,0x0,0x1c00000,0x0,0x0,0x1,0xc00001e0,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x1e0000,0x3e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x1e0,0x3c000,0x0,0x0,0x1f00000,
      0x0,0x780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0xfe0100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0xf0007fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe0000000,
      0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x1f,0x800000f0,0x1f80,0x0,0x0,0x0,0x0,
      0x78000000,0xf0000070,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3ffe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000,
      0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0xf00,0x1e0000,0x3c000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x1e0,0x7c000,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x78,0x0,0x0,0x0,0x0,0x7fff80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78000000,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4003,0xe0000000,0x0,0x1f000,0x0,0x0,
      0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x1,0xf0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0x70000001,0xf00000e0,
      0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,
      0x0,0x0,0x3c,0xff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000,0x0,0x0,0x1,0xc00003ff,
      0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00,0x1e0000,
      0x7c000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0xf0,0x78000,0x0,0x0,0x3e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf8,0x0,
      0x0,0x0,0x0,0x1fff80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,
      0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780f,0xc0000000,0x0,0x3e000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,
      0x0,0x0,0x0,0x0,0x3,0xe0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0xf0000103,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x21e00000,0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e00,0x1e0000,0xf8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,
      0xf8,0xf8000,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x1fe00,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x7fff,0xc0000000,0x0,0x3ffe000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0xe0000000,0x7,0xfc0000f0,
      0x3fe00,0x0,0x0,0x0,0x0,0x600001ff,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,
      0x3fe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x7fe00,0x1e0000,0x1ff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff,0x80000000,0x0,0x3ffc000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,
      0x0,0x0,0x0,0x0,0x7f,0xc0000000,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x0,0x0,0x1ff,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x3fc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fe,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fe,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fc00,0x1e0000,0x1ff0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x3ffe,0x0,0x0,0x3ff8000,0x0,0x0,0x0,
      0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0x80000000,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x80000000,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x3f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fc,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fc,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f800,0x1e0000,0x1fe0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f8,0x0,0x0,0x3fe0000,
      0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7e,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0xfe,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e000,0x1e0000,0x1f80000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };

    // Definition of a 40x38 'danger' color logo.
    const unsigned char logo40x38[4576] = {
      177,200,200,200,3,123,123,0,36,200,200,200,1,123,123,0,2,255,255,0,1,189,189,189,1,0,0,0,34,200,200,200,
      1,123,123,0,4,255,255,0,1,189,189,189,1,0,0,0,1,123,123,123,32,200,200,200,1,123,123,0,5,255,255,0,1,0,0,
      0,2,123,123,123,30,200,200,200,1,123,123,0,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,29,200,200,200,
      1,123,123,0,7,255,255,0,1,0,0,0,2,123,123,123,28,200,200,200,1,123,123,0,8,255,255,0,1,189,189,189,1,0,0,0,
      2,123,123,123,27,200,200,200,1,123,123,0,9,255,255,0,1,0,0,0,2,123,123,123,26,200,200,200,1,123,123,0,10,255,
      255,0,1,189,189,189,1,0,0,0,2,123,123,123,25,200,200,200,1,123,123,0,3,255,255,0,1,189,189,189,3,0,0,0,1,189,
      189,189,3,255,255,0,1,0,0,0,2,123,123,123,24,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,3,255,255,0,1,189,
      189,189,1,0,0,0,2,123,123,123,23,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,4,255,255,0,1,0,0,0,2,123,123,123,
      22,200,200,200,1,123,123,0,5,255,255,0,5,0,0,0,4,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,21,200,200,200,
      1,123,123,0,5,255,255,0,5,0,0,0,5,255,255,0,1,0,0,0,2,123,123,123,20,200,200,200,1,123,123,0,6,255,255,0,5,0,0,
      0,5,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,19,200,200,200,1,123,123,0,6,255,255,0,1,123,123,0,3,0,0,0,1,
      123,123,0,6,255,255,0,1,0,0,0,2,123,123,123,18,200,200,200,1,123,123,0,7,255,255,0,1,189,189,189,3,0,0,0,1,189,
      189,189,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,17,200,200,200,1,123,123,0,8,255,255,0,3,0,0,0,8,255,255,
      0,1,0,0,0,2,123,123,123,16,200,200,200,1,123,123,0,9,255,255,0,1,123,123,0,1,0,0,0,1,123,123,0,8,255,255,0,1,189,
      189,189,1,0,0,0,2,123,123,123,15,200,200,200,1,123,123,0,9,255,255,0,1,189,189,189,1,0,0,0,1,189,189,189,9,255,255,
      0,1,0,0,0,2,123,123,123,14,200,200,200,1,123,123,0,11,255,255,0,1,0,0,0,10,255,255,0,1,189,189,189,1,0,0,0,2,123,
      123,123,13,200,200,200,1,123,123,0,23,255,255,0,1,0,0,0,2,123,123,123,12,200,200,200,1,123,123,0,11,255,255,0,1,189,
      189,189,2,0,0,0,1,189,189,189,9,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,11,200,200,200,1,123,123,0,11,255,255,
      0,4,0,0,0,10,255,255,0,1,0,0,0,2,123,123,123,10,200,200,200,1,123,123,0,12,255,255,0,4,0,0,0,10,255,255,0,1,189,189,
      189,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,12,255,255,0,1,189,189,189,2,0,0,0,1,189,189,189,11,255,255,0,1,
      0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,27,255,255,0,1,0,0,0,3,123,123,123,8,200,200,200,1,123,123,0,26,255,
      255,0,1,189,189,189,1,0,0,0,3,123,123,123,9,200,200,200,1,123,123,0,24,255,255,0,1,189,189,189,1,0,0,0,4,123,123,
      123,10,200,200,200,1,123,123,0,24,0,0,0,5,123,123,123,12,200,200,200,27,123,123,123,14,200,200,200,25,123,123,123,86,
      200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0};

    //! Set/get output stream for CImg library messages.
    inline std::FILE* output(std::FILE *file) {
      static std::FILE *res = stderr;
      if (file) res = file;
      return res;
    }

    //! Display a warning message.
    /**
       \param format : C-string describing the format of the message, as in <tt>std::printf()</tt>.
    **/
    inline void warn(const char *const format, ...) {
      if (cimg::exception_mode()>=1) {
        char message[16384] = { 0 };
        std::va_list ap;
        va_start(ap,format);
        cimg_vsnprintf(message,sizeof(message),format,ap);
        va_end(ap);
#ifdef cimg_strict_warnings
        throw CImgWarningException(message);
#else
        std::fprintf(cimg::output(),"\n%s[CImg] *** Warning ***%s%s",cimg::t_red,cimg::t_normal,message);
#endif
      }
    }

    // Execute an external system command.
    /**
       \note This function is similar to <tt>std::system()</tt>
       and is here because using the <tt>std::</tt> version on
       Windows may open undesired consoles.
    **/
    inline int system(const char *const command, const char *const module_name=0) {
#if cimg_OS==2
      PROCESS_INFORMATION pi;
      STARTUPINFO si;
      std::memset(&pi,0,sizeof(PROCESS_INFORMATION));
      std::memset(&si,0,sizeof(STARTUPINFO));
      GetStartupInfo(&si);
      si.cb = sizeof(si);
      si.wShowWindow = SW_HIDE;
      si.dwFlags |= SW_HIDE;
      const BOOL res = CreateProcess((LPCTSTR)module_name,(LPTSTR)command,0,0,FALSE,0,0,0,&si,&pi);
      if (res) {
        WaitForSingleObject(pi.hProcess, INFINITE);
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);
        return 0;
      } else
#endif
        return std::system(command);
      return module_name?0:1;
    }

    //! Get a reference to a temporary variable of type T.
    template<typename T>
    inline T& temporary(const T&) {
      static T temp;
      return temp;
    }

    //! Exchange values of variables \p a and \p b.
    template<typename T>
    inline void swap(T& a, T& b) { T t = a; a = b; b = t; }

    //! Exchange values of variables (\p a1,\p a2) and (\p b1,\p b2).
    template<typename T1, typename T2>
    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2) {
      cimg::swap(a1,b1); cimg::swap(a2,b2);
    }

    //! Exchange values of variables (\p a1,\p a2,\p a3) and (\p b1,\p b2,\p b3).
    template<typename T1, typename T2, typename T3>
    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3) {
      cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3);
    }

    //! Exchange values of variables (\p a1,\p a2,...,\p a4) and (\p b1,\p b2,...,\p b4).
    template<typename T1, typename T2, typename T3, typename T4>
    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4) {
      cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4);
    }

    //! Exchange values of variables (\p a1,\p a2,...,\p a5) and (\p b1,\p b2,...,\p b5).
    template<typename T1, typename T2, typename T3, typename T4, typename T5>
    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5) {
      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5);
    }

    //! Exchange values of variables (\p a1,\p a2,...,\p a6) and (\p b1,\p b2,...,\p b6).
    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6) {
      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6);
    }

    //! Exchange values of variables (\p a1,\p a2,...,\p a7) and (\p b1,\p b2,...,\p b7).
    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6,
                     T7& a7, T7& b7) {
      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6); cimg::swap(a7,b7);
    }

    //! Exchange values of variables (\p a1,\p a2,...,\p a8) and (\p b1,\p b2,...,\p b8).
    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6,
                     T7& a7, T7& b7, T8& a8, T8& b8) {
      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7); cimg::swap(a8,b8);
    }

    //! Get the current endianness of the CPU.
    /**
       \return \c false for "Little Endian", \c true for "Big Endian".
    **/
    inline bool endianness() {
      const int x = 1;
      return ((unsigned char*)&x)[0]?false:true;
    }

    //! Invert endianness of a memory buffer.
    template<typename T>
    inline void invert_endianness(T* const buffer, const unsigned int size) {
      if (size) switch (sizeof(T)) {
      case 1 : break;
      case 2 : { for (unsigned short *ptr = (unsigned short*)buffer+size; ptr>(unsigned short*)buffer; ) {
        const unsigned short val = *(--ptr);
        *ptr = (unsigned short)((val>>8)|((val<<8)));
      }
      } break;
      case 4 : { for (unsigned int *ptr = (unsigned int*)buffer+size; ptr>(unsigned int*)buffer; ) {
        const unsigned int val = *(--ptr);
        *ptr = (val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24);
      }
      } break;
      default : { for (T* ptr = buffer+size; ptr>buffer; ) {
        unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T);
        for (int i = 0; i<(int)sizeof(T)/2; ++i) swap(*(pb++),*(--pe));
      }
      }
      }
    }

    //! Invert endianness of a single variable.
    template<typename T>
    inline T& invert_endianness(T& a) {
      invert_endianness(&a,1);
      return a;
    }

    // Conversion function to gain more precision in storage of unsigned ints as floats.
    inline unsigned int float2uint(const float f) {
      int tmp = 0;
      std::memcpy(&tmp,&f,sizeof(float));
      if (tmp>=0) return (unsigned int)f;
      unsigned int u;
      std::memcpy(&u,&f,sizeof(float));  // use memcpy instead of assignment to avoid wrong optimizations with g++.
      return ((u)<<1)>>1; // set sign bit to 0.
    }

    inline float uint2float(const unsigned int u) {
      if (u<(1U<<19)) return (float)u;  // Consider safe storage until 19bits (i.e 524287).
      float f;
      const unsigned int v = u|(1U<<(8*sizeof(unsigned int)-1)); // set sign bit to 1.
      std::memcpy(&f,&v,sizeof(float)); // use memcpy instead of simple assignment to avoir wrong optimizations with g++.
      return f;
    }

    //! Get the value of a system timer with a millisecond precision.
    inline unsigned long time() {
#if cimg_OS==1
      struct timeval st_time;
      gettimeofday(&st_time,0);
      return (unsigned long)(st_time.tv_usec/1000 + st_time.tv_sec*1000);
#elif cimg_OS==2
      static SYSTEMTIME st_time;
      GetSystemTime(&st_time);
      return (unsigned long)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));
#else
      return 0;
#endif
    }

    // Implement a tic/toc mechanism to display elapsed time of algorithms.
    inline unsigned long tictoc(const bool is_tic) {
      static unsigned long t0 = 0;
      const unsigned long t = cimg::time();
      if (is_tic) return (t0 = t);
      const unsigned long dt = t>=t0?(t - t0):cimg::type<unsigned long>::max();
      const unsigned int
        edays = (unsigned int)(dt/86400000.0),
        ehours = (unsigned int)((dt - edays*86400000.0)/3600000.0),
        emin = (unsigned int)((dt - edays*86400000.0 - ehours*3600000.0)/60000.0),
        esec = (unsigned int)((dt - edays*86400000.0 - ehours*3600000.0 - emin*60000.0)/1000.0),
        ems = (unsigned int)(dt - edays*86400000.0 - ehours*3600000.0 - emin*60000.0 - esec*1000.0);
      if (!edays && !ehours && !emin && !esec)
        std::fprintf(cimg::output(),"%s[CImg] Elapsed time : %u ms%s\n",cimg::t_red,ems,cimg::t_normal);
      else {
        if (!edays && !ehours && !emin)
          std::fprintf(cimg::output(),"%s[CImg] Elapsed time : %u sec %u ms%s\n",cimg::t_red,esec,ems,cimg::t_normal);
        else {
          if (!edays && !ehours)
            std::fprintf(cimg::output(),"%s[CImg] Elapsed time : %u min %u sec %u ms%s\n",cimg::t_red,emin,esec,ems,cimg::t_normal);
          else{
            if (!edays)
              std::fprintf(cimg::output(),"%s[CImg] Elapsed time : %u hours %u min %u sec %u ms%s\n",cimg::t_red,ehours,emin,esec,ems,cimg::t_normal);
            else{
              std::fprintf(cimg::output(),"%s[CImg] Elapsed time : %u days %u hours %u min %u sec %u ms%s\n",cimg::t_red,edays,ehours,emin,esec,ems,cimg::t_normal);
            }
          }
        }
      }
      return t;
    }

    inline unsigned long tic() {
      return cimg::tictoc(true);
    }

    inline unsigned long toc() {
      return cimg::tictoc(false);
    }

    //! Sleep for a certain numbers of milliseconds.
    /**
       This function frees the CPU ressources during the sleeping time.
       It may be used to temporize your program properly, without wasting CPU time.
    **/
    inline void sleep(const unsigned int milliseconds) {
#if cimg_OS==1
      struct timespec tv;
      tv.tv_sec = milliseconds/1000;
      tv.tv_nsec = (milliseconds%1000)*1000000;
      nanosleep(&tv,0);
#elif cimg_OS==2
      Sleep(milliseconds);
#endif
    }

    inline unsigned int _sleep(const unsigned int milliseconds, unsigned long& timer) {
      if (!timer) timer = cimg::time();
      const unsigned long current_time = cimg::time();
      if (current_time>=timer+milliseconds) { timer = current_time; return 0; }
      const unsigned long time_diff = timer + milliseconds - current_time;
      timer = current_time + time_diff;
      cimg::sleep(time_diff);
      return (unsigned int)time_diff;
    }

    //! Wait for a certain number of milliseconds since the last call.
    /**
       This function is equivalent to sleep() but the waiting time is computed with regard to the last call
       of wait(). It may be used to temporize your program properly.
    **/
    inline unsigned int wait(const unsigned int milliseconds) {
      static unsigned long timer = 0;
      if (!timer) timer = cimg::time();
      return _sleep(milliseconds,timer);
    }

    // Use a specific srand initialization to avoid multi-threads to have to the
    // same series of random numbers (executed only once for a single program).
    inline void srand() {
      static bool first_time = true;
      if (first_time) {
        std::srand(cimg::time());
        unsigned char *const rand_ptr = new unsigned char[sizeof(unsigned int)+std::rand()%2048];
        std::srand((unsigned int)std::rand() + *(unsigned int*)(void*)rand_ptr);
        delete[] rand_ptr;
        first_time = false;
      }
    }

    //! Get a left bitwise-rotated number.
    template<typename T>
    inline T rol(const T a, const unsigned int n=1) {
      return n?(T)((a<<n)|(a>>((sizeof(T)<<3)-n))):a;
    }

    inline float rol(const float a, const unsigned int n=1) {
      return (float)rol((int)a,n);
    }

    inline double rol(const double a, const unsigned int n=1) {
      return (double)rol((long)a,n);
    }

    //! Get a right bitwise-rotated number.
    template<typename T>
    inline T ror(const T a, const unsigned int n=1) {
      return n?(T)((a>>n)|(a<<((sizeof(T)<<3)-n))):a;
    }

    inline float ror(const float a, const unsigned int n=1) {
      return (float)ror((int)a,n);
    }

    inline double ror(const double a, const unsigned int n=1) {
      return (double)ror((long)a,n);
    }

    //! Get the absolute value of a number.
    /**
       \note This function is different from <tt>std::abs()</tt> or <tt>std::fabs()</tt>
       because it is able to consider a variable of any type, without cast needed.
    **/
    template<typename T>
    inline T abs(const T a) {
      return a>=0?a:-a;
    }
    inline bool abs(const bool a) {
      return a;
    }
    inline unsigned char abs(const unsigned char a) {
      return a;
    }
    inline unsigned short abs(const unsigned short a) {
      return a;
    }
    inline unsigned int abs(const unsigned int a) {
      return a;
    }
    inline unsigned long abs(const unsigned long a) {
      return a;
    }
    inline double abs(const double a) {
      return std::fabs(a);
    }
    inline float abs(const float a) {
      return (float)std::fabs((double)a);
    }
    inline int abs(const int a) {
      return std::abs(a);
    }

    //! Get the square of a number.
    template<typename T>
    inline T sqr(const T val) {
      return val*val;
    }

    //! Get <tt>1 + log_10(x)</tt>.
    inline int xln(const int x) {
      return x>0?(int)(1+std::log10((double)x)):1;
    }

    //! Get the minimum value between two numbers.
    template<typename t1, typename t2>
    inline typename cimg::superset<t1,t2>::type min(const t1& a, const t2& b) {
      typedef typename cimg::superset<t1,t2>::type t1t2;
      return (t1t2)(a<=b?a:b);
    }

    //! Get the minimum value between three numbers.
    template<typename t1, typename t2, typename t3>
    inline typename cimg::superset2<t1,t2,t3>::type min(const t1& a, const t2& b, const t3& c) {
      typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
      return (t1t2t3)cimg::min(cimg::min(a,b),c);
    }

    //! Get the minimum value between four numbers.
    template<typename t1, typename t2, typename t3, typename t4>
    inline typename cimg::superset3<t1,t2,t3,t4>::type min(const t1& a, const t2& b, const t3& c, const t4& d) {
      typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
      return (t1t2t3t4)cimg::min(cimg::min(a,b,c),d);
    }

    //! Get the maximum value between two numbers.
    template<typename t1, typename t2>
    inline typename cimg::superset<t1,t2>::type max(const t1& a, const t2& b) {
      typedef typename cimg::superset<t1,t2>::type t1t2;
      return (t1t2)(a>=b?a:b);
    }

    //! Get the maximum value between three numbers.
    template<typename t1, typename t2, typename t3>
    inline typename cimg::superset2<t1,t2,t3>::type max(const t1& a, const t2& b, const t3& c) {
      typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
      return (t1t2t3)cimg::max(cimg::max(a,b),c);
    }

    //! Get the maximum value between four numbers.
    template<typename t1, typename t2, typename t3, typename t4>
    inline typename cimg::superset3<t1,t2,t3,t4>::type max(const t1& a, const t2& b, const t3& c, const t4& d) {
      typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
      return (t1t2t3t4)cimg::max(cimg::max(a,b,c),d);
    }

    //! Get the sign of a number.
    template<typename T>
    inline T sign(const T x) {
      return (x<0)?(T)(-1):(x==0?(T)0:(T)1);
    }

    //! Get the nearest power of 2 higher than a given number.
    template<typename T>
    inline unsigned int nearest_pow2(const T x) {
      unsigned int i = 1;
      while (x>i) i<<=1;
      return i;
    }

    //! Get the sinc() of a given number.
    inline double sinc(const double x) {
      return x?std::sin(x)/x:1;
    }

    //! Get the modulo of a number.
    /**
       \note This modulo function accepts negative and floating-points modulo numbers, as well as
       variable of any type.
    **/
    template<typename T>
    inline T mod(const T& x, const T& m) {
      const double dx = (double)x, dm = (double)m;
      if (x<0) { return (T)(dm+dx+dm*std::floor(-dx/dm)); }
      return (T)(dx-dm*std::floor(dx/dm));
    }
    inline int mod(const bool x, const bool m) {
      return m?(x?1:0):0;
    }
    inline int mod(const char x, const char m) {
      return x>=0?x%m:(x%m?m+x%m:0);
    }
    inline int mod(const short x, const short m) {
      return x>=0?x%m:(x%m?m+x%m:0);
    }
    inline int mod(const int x, const int m) {
      return x>=0?x%m:(x%m?m+x%m:0);
    }
    inline int mod(const long x, const long m) {
      return x>=0?x%m:(x%m?m+x%m:0);
    }
    inline int mod(const unsigned char x, const unsigned char m) {
      return x%m;
    }
    inline int mod(const unsigned short x, const unsigned short m) {
      return x%m;
    }
    inline int mod(const unsigned int x, const unsigned int m) {
      return x%m;
    }
    inline int mod(const unsigned long x, const unsigned long m) {
      return x%m;
    }

    //! Get the minmod of two numbers.
    /**
       <i>minmod(\p a,\p b)</i> is defined to be :
       - <i>minmod(\p a,\p b) = min(\p a,\p b)</i>, if \p a and \p b have the same sign.
       - <i>minmod(\p a,\p b) = 0</i>, if \p a and \p b have different signs.
    **/
    template<typename T>
    inline T minmod(const T a, const T b) {
      return a*b<=0?0:(a>0?(a<b?a:b):(a<b?b:a));
    }

    //! Get a random variable between [0,1] with respect to an uniform distribution.
    inline double rand() {
      cimg::srand();
      return (double)std::rand()/RAND_MAX;
    }

    //! Get a random variable between [-1,1] with respect to an uniform distribution.
    inline double crand() {
      return 1-2*cimg::rand();
    }

    //! Get a random variable following a gaussian distribution and a standard deviation of 1.
    inline double grand() {
      double x1, w;
      do {
        const double x2 = 2*cimg::rand() - 1.0;
        x1 = 2*cimg::rand()-1.0;
        w = x1*x1 + x2*x2;
      } while (w<=0 || w>=1.0);
      return x1*std::sqrt((-2*std::log(w))/w);
    }

    //! Get a random variable following a Poisson distribution of parameter z.
    inline unsigned int prand(const double z) {
      if (z<=1.0e-10) return 0;
      if (z>100) return (unsigned int)((std::sqrt(z) * cimg::grand()) + z);
      unsigned int k = 0;
      const double y = std::exp(-z);
      for (double s = 1.0; s>=y; ++k) s*=cimg::rand();
      return k-1;
    }

    //! Get a rounded number.
    /**
       \param x : the number to be rounded.
       \param y : the rounding precision.
       \param rounding_type : the type of rounding (0=nearest, -1=backward, 1=forward).
       \return the rounded value, with the same type as parameter x.
    **/
    template<typename T>
    inline T round(const T x, const double y=1, const int rounding_type=0) {
      if (y<=0) return x;
      const double delta = cimg::mod((double)x,y);
      if (delta==0.0) return x;
      const double backward = x - delta, forward = backward + y;
      return (T)(rounding_type<0?backward:rounding_type>0?forward:2*delta<y?backward:2*delta>y?forward:x<0?backward:forward);
    }

    inline double _pythagore(double a, double b) {
      const double absa = cimg::abs(a), absb = cimg::abs(b);
      if (absa>absb) { const double tmp = absb/absa; return absa*std::sqrt(1.0+tmp*tmp); }
      else { const double tmp = absa/absb; return (absb==0?0:absb*std::sqrt(1.0+tmp*tmp)); }
    }

    //! Remove the 'case' of an ASCII character.
    inline char uncase(const char x) {
      return (char)((x<'A'||x>'Z')?x:x-'A'+'a');
    }

    //! Remove the 'case' of a C string.
    /**
       Acts in-place.
    **/
    inline void uncase(char *const string) {
      if (string) for (char *ptr = string; *ptr; ++ptr) *ptr = uncase(*ptr);
    }

    //! Read a double number from a C-string.
    /**
       \note This function is quite similar to <tt>std::atof()</tt>,
       but that it allows the retrieval of fractions as in "1/2".
    **/
    inline double atof(const char *const str) {
      double x = 0, y = 1;
      if (!str) return 0; else { std::sscanf(str,"%lf/%lf",&x,&y); return x/y; }
    }

    //! Compare the first \p n characters of two C-strings, ignoring the case.
    /**
       \note This function is defined since it is not provided by all compilers
       (not an ANSI function).
    **/
    inline int strncasecmp(const char *const s1, const char *const s2, const int l) {
      if (!l) return 0;
      if (!s1) return s2?-1:0;
      const char *ns1 = s1, *ns2 = s2;
      int k, diff = 0; for (k = 0; k<l && !(diff = uncase(*ns1)-uncase(*ns2)); ++k) { ++ns1; ++ns2; }
      return k!=l?diff:0;
    }

    //! Compare two C-strings, ignoring the case.
    /**
       \note This function is defined since it is not provided by all compilers
       (not an ANSI function).
    **/
    inline int strcasecmp(const char *const s1, const char *const s2) {
      if (!s1) return s2?-1:0;
      const unsigned int l1 = std::strlen(s1), l2 = std::strlen(s2);
      return cimg::strncasecmp(s1,s2,1+(l1<l2?l1:l2));
    }

    //! Remove useless delimiters on the borders of a C-string
    inline bool strpare(char *const s, const char delimiter=' ', const bool symmetric=false, const bool is_iterative=false) {
      if (!s) return false;
      const int l = (int)std::strlen(s);
      int p, q;
      if (symmetric) for (p = 0, q = l-1; p<q && s[p]==delimiter && s[q]==delimiter; ) { --q; ++p; if (!is_iterative) break; }
      else {
        for (p = 0; p<l && s[p]==delimiter; ) { ++p; if (!is_iterative) break; }
        for (q = l-1; q>p && s[q]==delimiter; ) { --q; if (!is_iterative) break; }
      }
      const int n = q - p + 1;
      if (n!=l) { std::memmove(s,s+p,n); s[n] = 0; return true; }
      return false;
    }

    //! Replace explicit escape sequences '\x' in C-strings.
    inline void strescape(char *const s) {
#define cimg_strescape(ci,co) case ci: *nd = co; ++ns; break;
      static unsigned int val = 0;
      for (char *ns = s, *nd = s; *ns || (bool)(*nd=0); ++nd) if (*ns=='\\') switch (*(++ns)) {
            cimg_strescape('n','\n');
            cimg_strescape('t','\t');
            cimg_strescape('v','\v');
            cimg_strescape('b','\b');
            cimg_strescape('r','\r');
            cimg_strescape('f','\f');
            cimg_strescape('a','\a');
            cimg_strescape('\\','\\');
            cimg_strescape('\?','\?');
            cimg_strescape('\'','\'');
            cimg_strescape('\"','\"');
          case 0 : *nd = 0; break;
          case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' :
            std::sscanf(ns,"%o",&val); while (*ns>='0' && *ns<='7') ++ns;
            *nd = val; break;
          case 'x':
            std::sscanf(++ns,"%x",&val); while ((*ns>='0' && *ns<='7') || (*ns>='a' && *ns<='f') || (*ns>='A' && *ns<='F')) ++ns;
            *nd = val; break;
          default : *nd = *(ns++);
          } else *nd = *(ns++);
    }

    // Get a temporary string describing the size of a buffer.
    inline const char *strbuffersize(const unsigned long size) {
      static char res[256] = { 0 };
      if (size<1024LU) cimg_snprintf(res,sizeof(res),"%lu byte%s",size,size>1?"s":"");
      else if (size<1024*1024LU) { const float nsize = size/1024.0f; cimg_snprintf(res,sizeof(res),"%.1f Kb",nsize); }
      else if (size<1024*1024*1024LU) { const float nsize = size/(1024*1024.0f); cimg_snprintf(res,sizeof(res),"%.1f Mb",nsize); }
      else { const float nsize = size/(1024*1024*1024.0f); cimg_snprintf(res,sizeof(res),"%.1f Gb",nsize); }
      return res;
    }

    //! Compute the basename of a filename.
    inline const char* basename(const char *const s)  {
      const char *p = 0;
      for (const char *np = s; np>=s && (p=np); np = std::strchr(np,cimg_file_separator)+1) {}
      return p;
    }

    // Generate a random filename.
    inline const char* filenamerand() {
      static char randomid[9] = { 0,0,0,0,0,0,0,0,0 };
      cimg::srand();
      for (unsigned int k = 0; k<8; ++k) {
        const int v = (int)std::rand()%3;
        randomid[k] = (char)(v==0?('0'+(std::rand()%10)):(v==1?('a'+(std::rand()%26)):('A'+(std::rand()%26))));
      }
      return randomid;
    }

    // Convert filename into a Windows-style filename.
    inline void winformat_string(char *const s) {
      if (s && *s) {
#if cimg_OS==2
        char *const ns = new char[MAX_PATH];
        if (GetShortPathNameA(s,ns,MAX_PATH)) std::strcpy(s,ns);
#endif
      }
    }

    //! Open a file, and check for possible errors.
    inline std::FILE *fopen(const char *const path, const char *const mode) {
      if (!path)
        throw CImgArgumentException("cimg::fopen() : Specified file path is (null).");
      if (!mode)
        throw CImgArgumentException("cimg::fopen() : File '%s', specified mode is (null).",
                                    path);
      std::FILE *res = 0;
      if (*path=='-' && path[1]=='.') {
        res = (*mode=='r')?stdin:stdout;
#if cimg_OS==2
        if (*mode && mode[1]=='b') { // Force stdin/stdout to be in binary mode.
          if (_setmode(_fileno(res),0x8000)==-1) res = 0;
        }
#endif
      } else res = std::fopen(path,mode);
      if (!res) throw CImgIOException("cimg::fopen() : Failed to open file '%s' with mode '%s'.",
                                      path,mode);
      return res;
    }

    //! Close a file, and check for possible errors.
    inline int fclose(std::FILE *file) {
      if (!file) warn("cimg::fclose() : Specified file is (null).");
      if (!file || file==stdin || file==stdout) return 0;
      const int errn = std::fclose(file);
      if (errn!=0) warn("cimg::fclose() : Error code %d returned during file closing.",
                        errn);
      return errn;
    }

    //! Get or set path to store temporary files.
    inline const char* temporary_path(const char *const user_path=0, const bool reinit_path=false) {
#define _cimg_test_temporary_path(p) \
      if (!path_found) { \
        cimg_snprintf(st_path,1024,"%s",p); \
        cimg_snprintf(tmp,sizeof(tmp),"%s%c%s",st_path,cimg_file_separator,filetmp); \
        if ((file=std::fopen(tmp,"wb"))!=0) { cimg::fclose(file); std::remove(tmp); path_found = true; } \
      }
      static char *st_path = 0;
      if (reinit_path) { delete[] st_path; st_path = 0; }
      if (user_path) {
        if (!st_path) st_path = new char[1024];
        std::memset(st_path,0,1024);
        std::strncpy(st_path,user_path,1023);
      } else if (!st_path) {
        st_path = new char[1024];
        std::memset(st_path,0,1024);
        bool path_found = false;
        char tmp[1024] = { 0 }, filetmp[512] = { 0 };
        std::FILE *file = 0;
        cimg_snprintf(filetmp,sizeof(filetmp),"%s.tmp",cimg::filenamerand());
        char *tmpPath = std::getenv("TMP");
        if (!tmpPath) { tmpPath = std::getenv("TEMP"); winformat_string(tmpPath); }
        if (tmpPath) _cimg_test_temporary_path(tmpPath);
#if cimg_OS==2
        _cimg_test_temporary_path("C:\\WINNT\\Temp");
        _cimg_test_temporary_path("C:\\WINDOWS\\Temp");
        _cimg_test_temporary_path("C:\\Temp");
        _cimg_test_temporary_path("C:");
        _cimg_test_temporary_path("D:\\WINNT\\Temp");
        _cimg_test_temporary_path("D:\\WINDOWS\\Temp");
        _cimg_test_temporary_path("D:\\Temp");
        _cimg_test_temporary_path("D:");
#else
        _cimg_test_temporary_path("/tmp");
        _cimg_test_temporary_path("/var/tmp");
#endif
        if (!path_found) {
          *st_path = 0;
          std::strncpy(tmp,filetmp,sizeof(tmp)-1);
          if ((file=std::fopen(tmp,"wb"))!=0) { cimg::fclose(file); std::remove(tmp); path_found = true; }
        }
        if (!path_found)
          throw CImgIOException("cimg::temporary_path() : Failed to locate path for writing temporary files.\n");
      }
      return st_path;
    }

    // Get or set path to the "Program files/" directory (windows only).
#if cimg_OS==2
    inline const char* programfiles_path(const char *const user_path=0, const bool reinit_path=false) {
      static char *st_path = 0;
      if (reinit_path) { delete[] st_path; st_path = 0; }
      if (user_path) {
        if (!st_path) st_path = new char[1024];
        std::memset(st_path,0,1024);
        std::strncpy(st_path,user_path,1023);
      } else if (!st_path) {
        st_path = new char[MAX_PATH];
        std::memset(st_path,0,MAX_PATH);
        // Note : in the following line, 0x26 = CSIDL_PROGRAM_FILES (not defined on every compiler).
#if !defined(__INTEL_COMPILER)
        if (!SHGetSpecialFolderPathA(0,st_path,0x0026,false)) {
          const char *const pfPath = std::getenv("PROGRAMFILES");
          if (pfPath) std::strncpy(st_path,pfPath,MAX_PATH-1);
          else std::strcpy(st_path,"C:\\PROGRA~1");
        }
#else
        std::strcpy(st_path,"C:\\PROGRA~1");
#endif
      }
      return st_path;
    }
#endif

    //! Get or set path to the ImageMagick's \c convert tool.
    inline const char* imagemagick_path(const char *const user_path=0, const bool reinit_path=false) {
      static char *st_path = 0;
      if (reinit_path) { delete[] st_path; st_path = 0; }
      if (user_path) {
        if (!st_path) st_path = new char[1024];
        std::memset(st_path,0,1024);
        std::strncpy(st_path,user_path,1023);
      } else if (!st_path) {
        st_path = new char[1024];
        std::memset(st_path,0,1024);
        bool path_found = false;
        std::FILE *file = 0;
#if cimg_OS==2
        const char *const pf_path = programfiles_path();
        if (!path_found) {
          std::strcpy(st_path,".\\convert.exe");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"%s\\IMAGEM~1.%.2d-\\convert.exe",pf_path,k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"%s\\IMAGEM~1.%d-Q\\convert.exe",pf_path,k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"%s\\IMAGEM~1.%d\\convert.exe",pf_path,k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"%s\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",pf_path,k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"%s\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",pf_path,k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"%s\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",pf_path,k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"C:\\IMAGEM~1.%.2d-\\convert.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"C:\\IMAGEM~1.%d-Q\\convert.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"C:\\IMAGEM~1.%d\\convert.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"C:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"C:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"C:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"D:\\IMAGEM~1.%.2d-\\convert.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"D:\\IMAGEM~1.%d-Q\\convert.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"D:\\IMAGEM~1.%d\\convert.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"D:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"D:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"D:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"convert.exe");
#else
        if (!path_found) {
          std::strcpy(st_path,"./convert");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"convert");
#endif
        winformat_string(st_path);
      }
      return st_path;
    }

    //! Get path of the GraphicsMagick's \c gm tool.
    inline const char* graphicsmagick_path(const char *const user_path=0, const bool reinit_path=false) {
      static char *st_path = 0;
      if (reinit_path) { delete[] st_path; st_path = 0; }
      if (user_path) {
        if (!st_path) st_path = new char[1024];
        std::memset(st_path,0,1024);
        std::strncpy(st_path,user_path,1023);
      } else if (!st_path) {
        st_path = new char[1024];
        std::memset(st_path,0,1024);
        bool path_found = false;
        std::FILE *file = 0;
#if cimg_OS==2
        const char *const pf_path = programfiles_path();
        if (!path_found) {
          std::strcpy(st_path,".\\gm.exe");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"%s\\GRAPHI~1.%.2d-\\gm.exe",pf_path,k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"%s\\GRAPHI~1.%d-Q\\gm.exe",pf_path,k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"%s\\GRAPHI~1.%d\\gm.exe",pf_path,k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"%s\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",pf_path,k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"%s\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",pf_path,k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"%s\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",pf_path,k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"C:\\GRAPHI~1.%.2d-\\gm.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"C:\\GRAPHI~1.%d-Q\\gm.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"C:\\GRAPHI~1.%d\\gm.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"C:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"C:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"C:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"D:\\GRAPHI~1.%.2d-\\gm.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"D:\\GRAPHI~1.%d-Q\\gm.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"D:\\GRAPHI~1.%d\\gm.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=10 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"D:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 9; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"D:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        for (int k = 32; k>=0 && !path_found; --k) {
          cimg_snprintf(st_path,sizeof(st_path),"D:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"gm.exe");
#else
        if (!path_found) {
          std::strcpy(st_path,"./gm");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"gm");
#endif
        winformat_string(st_path);
      }
      return st_path;
    }

    //! Get or set path of the \c XMedcon tool.
    inline const char* medcon_path(const char *const user_path=0, const bool reinit_path=false) {
      static char *st_path = 0;
      if (reinit_path) { delete[] st_path; st_path = 0; }
      if (user_path) {
        if (!st_path) st_path = new char[1024];
        std::memset(st_path,0,1024);
        std::strncpy(st_path,user_path,1023);
      } else if (!st_path) {
        st_path = new char[1024];
        std::memset(st_path,0,1024);
        bool path_found = false;
        std::FILE *file = 0;
#if cimg_OS==2
        const char *const pf_path = programfiles_path();
        if (!path_found) {
          std::strcpy(st_path,".\\medcon.exe");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) {
          cimg_snprintf(st_path,sizeof(st_path),"%s\\XMedCon\\bin\\medcon.bat",pf_path);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) {
          cimg_snprintf(st_path,sizeof(st_path),"%s\\XMedCon\\bin\\medcon.exe",pf_path);
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"medcon.exe");
#else
        if (!path_found) {
          std::strcpy(st_path,"./medcon");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"medcon");
#endif
        winformat_string(st_path);
      }
      return st_path;
    }

    //! Get or set path to the 'ffmpeg' command.
    inline const char *ffmpeg_path(const char *const user_path=0, const bool reinit_path=false) {
      static char *st_path = 0;
      if (reinit_path) { delete[] st_path; st_path = 0; }
      if (user_path) {
        if (!st_path) st_path = new char[1024];
        std::memset(st_path,0,1024);
        std::strncpy(st_path,user_path,1023);
      } else if (!st_path) {
        st_path = new char[1024];
        std::memset(st_path,0,1024);
        bool path_found = false;
        std::FILE *file = 0;
#if cimg_OS==2
        if (!path_found) {
          std::strcpy(st_path,".\\ffmpeg.exe");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"ffmpeg.exe");
#else
        if (!path_found) {
          std::strcpy(st_path,"./ffmpeg");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"ffmpeg");
#endif
        winformat_string(st_path);
      }
      return st_path;
    }

    //! Get or set path to the 'gzip' command.
    inline const char *gzip_path(const char *const user_path=0, const bool reinit_path=false) {
      static char *st_path = 0;
      if (reinit_path) { delete[] st_path; st_path = 0; }
      if (user_path) {
        if (!st_path) st_path = new char[1024];
        std::memset(st_path,0,1024);
        std::strncpy(st_path,user_path,1023);
      } else if (!st_path) {
        st_path = new char[1024];
        std::memset(st_path,0,1024);
        bool path_found = false;
        std::FILE *file = 0;
#if cimg_OS==2
        if (!path_found) {
          std::strcpy(st_path,".\\gzip.exe");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"gzip.exe");
#else
        if (!path_found) {
          std::strcpy(st_path,"./gzip");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"gzip");
#endif
        winformat_string(st_path);
      }
      return st_path;
    }

    //! Get or set path to the 'gunzip' command.
    inline const char *gunzip_path(const char *const user_path=0, const bool reinit_path=false) {
      static char *st_path = 0;
      if (reinit_path) { delete[] st_path; st_path = 0; }
      if (user_path) {
        if (!st_path) st_path = new char[1024];
        std::memset(st_path,0,1024);
        std::strncpy(st_path,user_path,1023);
      } else if (!st_path) {
        st_path = new char[1024];
        std::memset(st_path,0,1024);
        bool path_found = false;
        std::FILE *file = 0;
#if cimg_OS==2
        if (!path_found) {
          std::strcpy(st_path,".\\gunzip.exe");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"gunzip.exe");
#else
        if (!path_found) {
          std::strcpy(st_path,"./gunzip");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"gunzip");
#endif
        winformat_string(st_path);
      }
      return st_path;
    }

    //! Get or set path to the 'dcraw' command.
    inline const char *dcraw_path(const char *const user_path=0, const bool reinit_path=false) {
      static char *st_path = 0;
      if (reinit_path) { delete[] st_path; st_path = 0; }
      if (user_path) {
        if (!st_path) st_path = new char[1024];
        std::memset(st_path,0,1024);
        std::strncpy(st_path,user_path,1023);
      } else if (!st_path) {
        st_path = new char[1024];
        std::memset(st_path,0,1024);
        bool path_found = false;
        std::FILE *file = 0;
#if cimg_OS==2
        if (!path_found) {
          std::strcpy(st_path,".\\dcraw.exe");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"dcraw.exe");
#else
        if (!path_found) {
          std::strcpy(st_path,"./dcraw");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"dcraw");
#endif
        winformat_string(st_path);
      }
      return st_path;
    }

    //! Get or set path to the 'wget' command.
    inline const char *wget_path(const char *const user_path=0, const bool reinit_path=false) {
      static char *st_path = 0;
      if (reinit_path) { delete[] st_path; st_path = 0; }
      if (user_path) {
        if (!st_path) st_path = new char[1024];
        std::memset(st_path,0,1024);
        std::strncpy(st_path,user_path,1023);
      } else if (!st_path) {
        st_path = new char[1024];
        std::memset(st_path,0,1024);
        bool path_found = false;
        std::FILE *file = 0;
#if cimg_OS==2
        if (!path_found) {
          std::strcpy(st_path,".\\wget.exe");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"wget.exe");
#else
        if (!path_found) {
          std::strcpy(st_path,"./wget");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"wget");
#endif
        winformat_string(st_path);
      }
      return st_path;
    }

    //! Get or set path to the 'curl' command.
    inline const char *curl_path(const char *const user_path=0, const bool reinit_path=false) {
      static char *st_path = 0;
      if (reinit_path) { delete[] st_path; st_path = 0; }
      if (user_path) {
        if (!st_path) st_path = new char[1024];
        std::memset(st_path,0,1024);
        std::strncpy(st_path,user_path,1023);
      } else if (!st_path) {
        st_path = new char[1024];
        std::memset(st_path,0,1024);
        bool path_found = false;
        std::FILE *file = 0;
#if cimg_OS==2
        if (!path_found) {
          std::strcpy(st_path,".\\curl.exe");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"curl.exe");
#else
        if (!path_found) {
          std::strcpy(st_path,"./curl");
          if ((file=std::fopen(st_path,"r"))!=0) { cimg::fclose(file); path_found = true; }
        }
        if (!path_found) std::strcpy(st_path,"curl");
#endif
        winformat_string(st_path);
      }
      return st_path;
    }

    //! Split a filename into two strings 'body' and 'extension'.
    inline const char *split_filename(const char *const filename, char *const body=0) {
      if (!filename) { if (body) *body = 0; return 0; }
      const char *p = 0; for (const char *np = filename; np>=filename && (p=np); np = std::strchr(np,'.')+1) {}
      if (p==filename) {
        if (body) std::strcpy(body,filename);
        return filename + std::strlen(filename);
      }
      const unsigned int l = p - filename - 1;
      if (body) { std::memcpy(body,filename,l); body[l] = 0; }
      return p;
    }

    //! Create a numbered version of a filename.
    inline char* number_filename(const char *const filename, const int number, const unsigned int n, char *const string) {
      if (!filename) { if (string) *string = 0; return 0; }
      char format[1024] = { 0 }, body[1024] = { 0 };
      const char *const ext = cimg::split_filename(filename,body);
      if (n>0) cimg_snprintf(format,sizeof(format),"%s_%%.%ud.%s",body,n,ext);
      else cimg_snprintf(format,sizeof(format),"%s_%%d.%s",body,ext);
      std::sprintf(string,format,number);
      return string;
    }

    //! Try to guess the image format of a filename, using the magic numbers in its header.
    inline const char *file_type(std::FILE *const file, const char *const filename) {
      if (!file && !filename)
        throw CImgArgumentException("cimg::file_type() : Specified filename is (null).");
      static const char
        *const _pnm = "pnm",
        *const _pfm = "pfm",
        *const _bmp = "bmp",
        *const _gif = "gif",
        *const _jpg = "jpg",
        *const _off = "off",
        *const _pan = "pan",
        *const _png = "png",
        *const _tif = "tif",
        *const _inr = "inr",
        *const _dcm = "dcm";
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
      const char *f_type = 0, *head;
      char header[2048] = { 0 }, item[1024] = { 0 };
      const unsigned char *const uheader = (unsigned char*)header;
      int err; char cerr;
      const unsigned int siz = (unsigned int)std::fread(header,2048,1,nfile);   // Read first 2048 bytes.
      if (!file) cimg::fclose(nfile);

      if (!std::strncmp(header,"OFF\n",4)) f_type = _off; // Check for OFF format.
      else if (!std::strncmp(header,"#INRIMAGE",9)) f_type = _inr; // Check for INRIMAGE format.
      else if (!std::strncmp(header,"PANDORE",7)) f_type = _pan; // Check for PANDORE format.
      else if (!std::strncmp(header+128,"DICM",4)) f_type = _dcm; // Check for DICOM format.
      else if (uheader[0]==0xFF && uheader[1]==0xD8 && uheader[2]==0xFF) f_type = _jpg;  // Check for JPEG format.
      else if (header[0]=='B' && header[1]=='M') f_type = _bmp;  // Check for BMP format.
      else if (header[0]=='G' && header[1]=='I' && header[2]=='F' && header[3]=='8' && header[5]=='a' && // Check for GIF format.
               (header[4]=='7' || header[4]=='9')) f_type = _gif;
      else if (uheader[0]==0x89 && uheader[1]==0x50 && uheader[2]==0x4E && uheader[3]==0x47 &&  // Check for PNG format.
               uheader[4]==0x0D && uheader[5]==0x0A && uheader[6]==0x1A && uheader[7]==0x0A) f_type = _png;
      else if ((uheader[0]==0x49 && uheader[1]==0x49) || (uheader[0]==0x4D && uheader[1]==0x4D)) f_type = _tif; // Check for TIFF format.
      else { // Check for PNM or PFM format.
        head = header;
        while (head<header+siz && (err=std::sscanf(head,"%1023[^\n]",item))!=EOF && (*item=='#' || !err))
          head+=1+(err?std::strlen(item):0);
        if (std::sscanf(item," P%d",&err)==1) f_type = _pnm;
        else if (std::sscanf(item," P%c",&cerr)==1 && (cerr=='f' || cerr=='F')) f_type = _pfm;
      }
      return f_type;
    }

    //! Read file data, and check for possible errors.
    template<typename T>
    inline int fread(T *const ptr, const unsigned int nmemb, std::FILE *stream) {
      if (!ptr || nmemb<=0 || !stream)
        throw CImgArgumentException("cimg::fread() : Invalid reading request of %u %s%s from file %p to buffer %p.",
                                    nmemb,cimg::type<T>::string(),nmemb>1?"s":"",stream,ptr);

      const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
      unsigned int to_read = nmemb, al_read = 0, l_to_read = 0, l_al_read = 0;
      do {
        l_to_read = (to_read*sizeof(T))<wlimitT?to_read:wlimit;
        l_al_read = (unsigned int)std::fread((void*)(ptr+al_read),sizeof(T),l_to_read,stream);
        al_read+=l_al_read;
        to_read-=l_al_read;
      } while (l_to_read==l_al_read && to_read>0);
      if (to_read>0)
        warn("cimg::fread() : Only %u/%u elements could be read from file.",
             al_read,nmemb);
      return al_read;
    }

    //! Write data to a file, and check for possible errors.
    template<typename T>
    inline int fwrite(const T *ptr, const unsigned int nmemb, std::FILE *stream) {
      if (!ptr || !stream)
        throw CImgArgumentException("cimg::fwrite() : Invalid writing request of %u %s%s from buffer %p to file %p.",
                                    nmemb,cimg::type<T>::string(),nmemb>1?"s":"",ptr,stream);
      if (nmemb<=0) return 0;
      const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
      unsigned int to_write = nmemb, al_write = 0, l_to_write = 0, l_al_write = 0;
      do {
        l_to_write = (to_write*sizeof(T))<wlimitT?to_write:wlimit;
        l_al_write = (unsigned int)std::fwrite((void*)(ptr+al_write),sizeof(T),l_to_write,stream);
        al_write+=l_al_write;
        to_write-=l_al_write;
      } while (l_to_write==l_al_write && to_write>0);
      if (to_write>0)
        warn("cimg::fwrite() : Only %u/%u elements could be written in file.",
             al_write,nmemb);
      return al_write;
    }

    //! Load file from network as a local temporary file, using 'wget' or 'curl' if found.
    inline char *load_network_external(const char *const filename, char *const filename_local) {
      if (!filename)
        throw CImgArgumentException("cimg::load_network_external() : Specified filename is (null).");
      if (!filename_local)
        throw CImgArgumentException("cimg::load_network_external() : Specified destination string is (null).");
      const char *const _ext = cimg::split_filename(filename), *const ext = (*_ext && _ext>filename)?_ext-1:_ext;
      char command[1024] = { 0 };
      std::FILE *file = 0;
      *filename_local = 0;
      do {
        cimg_snprintf(filename_local,512,"%s%c%s%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext);
        if ((file=std::fopen(filename_local,"rb"))!=0) cimg::fclose(file);
      } while (file);

      // Try with 'curl' first.
      cimg_snprintf(command,sizeof(command),"%s -f --silent --compressed -o \"%s\" \"%s\"",cimg::curl_path(),filename_local,filename);
      cimg::system(command);
      if (!(file = std::fopen(filename_local,"rb"))) {

        // Try with 'wget' else.
        cimg_snprintf(command,sizeof(command),"%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"",cimg::wget_path(),filename_local,filename);
        cimg::system(command);
        if (!(file = std::fopen(filename_local,"rb")))
          throw CImgIOException("cimg::load_network_external() : Failed to load file '%s' with external tools 'wget' or 'curl'.",filename);
        cimg::fclose(file);

        // Try gunzip it.
        cimg_snprintf(command,sizeof(command),"%s.gz",filename_local);
        std::rename(filename_local,command);
        cimg_snprintf(command,sizeof(command),"%s --quiet %s.gz",gunzip_path(),filename_local);
        cimg::system(command);
        file = std::fopen(filename_local,"rb");
        if (!file) {
          cimg_snprintf(command,sizeof(command),"%s.gz",filename_local);
          std::rename(command,filename_local);
          file = std::fopen(filename_local,"rb");
        }
      }
      std::fseek(file,0,SEEK_END); // Check if file size is 0.
      if (!(unsigned int)std::ftell(file))
        throw CImgIOException("cimg::load_network_external() : Failed to load file '%s' with external commands 'wget' or 'curl'.",filename);
      cimg::fclose(file);
      return filename_local;
    }

    inline const char* option(const char *const name, const int argc, const char *const *const argv,
                              const char *const defaut, const char *const usage, const bool reset_static) {
      static bool first = true, visu = false;
      if (reset_static) { first = true; return 0; }
      const char *res = 0;
      if (first) {
        first = false;
        visu = cimg::option("-h",argc,argv,(char*)0,(char*)0,false)!=0;
        visu |= cimg::option("-help",argc,argv,(char*)0,(char*)0,false)!=0;
        visu |= cimg::option("--help",argc,argv,(char*)0,(char*)0,false)!=0;
      }
      if (!name && visu) {
        if (usage) {
          std::fprintf(cimg::output(),"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal);
          std::fprintf(cimg::output()," : %s",usage);
          std::fprintf(cimg::output()," (%s, %s)\n\n",__DATE__,__TIME__);
        }
        if (defaut) std::fprintf(cimg::output(),"%s\n",defaut);
      }
      if (name) {
        if (argc>0) {
          int k = 0;
          while (k<argc && std::strcmp(argv[k],name)) ++k;
          res = (k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
        } else res = defaut;
        if (visu && usage) std::fprintf(cimg::output(),"    %s%-16s%s %-24s %s%s%s\n",
                                        cimg::t_bold,name,cimg::t_normal,res?res:"0",cimg::t_green,usage,cimg::t_normal);
      }
      return res;
    }

    inline const char* option(const char *const name, const int argc, const char *const *const argv,
                              const char *const defaut, const char *const usage=0) {
      return option(name,argc,argv,defaut,usage,false);
    }

    inline bool option(const char *const name, const int argc, const char *const *const argv,
                       const bool defaut, const char *const usage=0) {
      const char *const s = cimg::option(name,argc,argv,(char*)0);
      const bool res = s?(cimg::strcasecmp(s,"false") && cimg::strcasecmp(s,"off") && cimg::strcasecmp(s,"0")):defaut;
      cimg::option(name,0,0,res?"true":"false",usage);
      return res;
    }

    inline int option(const char *const name, const int argc, const char *const *const argv,
                      const int defaut, const char *const usage=0) {
      const char *const s = cimg::option(name,argc,argv,(char*)0);
      const int res = s?std::atoi(s):defaut;
      char tmp[256] = { 0 };
      cimg_snprintf(tmp,sizeof(tmp),"%d",res);
      cimg::option(name,0,0,tmp,usage);
      return res;
    }

    inline char option(const char *const name, const int argc, const char *const *const argv,
                       const char defaut, const char *const usage=0) {
      const char *const s = cimg::option(name,argc,argv,(char*)0);
      const char res = s?*s:defaut;
      char tmp[8] = { 0 };
      *tmp = res;
      cimg::option(name,0,0,tmp,usage);
      return res;
    }

    inline float option(const char *const name, const int argc, const char *const *const argv,
                        const float defaut, const char *const usage=0) {
      const char *const s = cimg::option(name,argc,argv,(char*)0);
      const float res = s?(float)cimg::atof(s):defaut;
      char tmp[256] = { 0 };
      cimg_snprintf(tmp,sizeof(tmp),"%g",res);
      cimg::option(name,0,0,tmp,usage);
      return res;
    }

    inline double option(const char *const name, const int argc, const char *const *const argv,
                         const double defaut, const char *const usage=0) {
      const char *const s = cimg::option(name,argc,argv,(char*)0);
      const double res = s?cimg::atof(s):defaut;
      char tmp[256] = { 0 };
      cimg_snprintf(tmp,sizeof(tmp),"%g",res);
      cimg::option(name,0,0,tmp,usage);
      return res;
    }

    inline const char* argument(const unsigned int nb, const int argc, const char *const *const argv, const unsigned int nb_singles=0, ...) {
      for (int k = 1, pos = 0; k<argc;) {
        const char *const item = argv[k];
        bool option = (*item=='-'), single_option = false;
        if (option) {
          va_list ap;
          va_start(ap,nb_singles);
          for (unsigned int i = 0; i<nb_singles; ++i) if (!cimg::strcasecmp(item,va_arg(ap,char*))) { single_option = true; break; }
          va_end(ap);
        }
        if (option) { ++k; if (!single_option) ++k; }
        else { if (pos++==(int)nb) return item; else ++k; }
      }
      return 0;
    }

    //! Print informations about %CImg environement variables.
    /**
       Printing is done on the standard error output.
    **/
    inline void info() {
      char tmp[1024] = { 0 };
      std::fprintf(cimg::output(),"\n %sCImg Library %u.%u.%u%s, compiled %s ( %s ) with the following flags :\n\n",
                   cimg::t_red,cimg_version/100,(cimg_version/10)%10,cimg_version%10,
                   cimg::t_normal,__DATE__,__TIME__);

      std::fprintf(cimg::output(),"  > Operating System :       %s%-13s%s %s('cimg_OS'=%d)%s\n",
                   cimg::t_bold,
                   cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknow"),
                   cimg::t_normal,cimg::t_green,
                   cimg_OS,
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > CPU endianness :         %s%s Endian%s\n",
                   cimg::t_bold,
                   cimg::endianness()?"Big":"Little",
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Verbosity mode :         %s%-13s%s %s('cimg_verbosity'=%d)%s\n",
                   cimg::t_bold,
                   cimg_verbosity==0?"Quiet":(cimg_verbosity==1?"Console":(cimg_verbosity==2?"Dialog":(cimg_verbosity==3?"Console+Warnings":"Dialog+Warnings"))),
                   cimg::t_normal,cimg::t_green,
                   cimg_verbosity,
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Stricts warnings :       %s%-13s%s %s('cimg_strict_warnings' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_strict_warnings
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Using VT100 messages :   %s%-13s%s %s('cimg_use_vt100' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_vt100
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Display type :           %s%-13s%s %s('cimg_display'=%d)%s\n",
                   cimg::t_bold,
                   cimg_display==0?"No display":cimg_display==1?"X11":cimg_display==2?"Windows GDI":"Unknown",
                   cimg::t_normal,cimg::t_green,
                   cimg_display,
                   cimg::t_normal);

#if cimg_display==1
      std::fprintf(cimg::output(),"  > Using XShm for X11 :     %s%-13s%s %s('cimg_use_xshm' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_xshm
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Using XRand for X11 :    %s%-13s%s %s('cimg_use_xrandr' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_xrandr
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);
#endif
      std::fprintf(cimg::output(),"  > Using OpenMP :           %s%-13s%s %s('cimg_use_openmp' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_openmp
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);
      std::fprintf(cimg::output(),"  > Using PNG library :      %s%-13s%s %s('cimg_use_png' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_png
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);
      std::fprintf(cimg::output(),"  > Using JPEG library :     %s%-13s%s %s('cimg_use_jpeg' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_jpeg
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Using TIFF library :     %s%-13s%s %s('cimg_use_tiff' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_tiff
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Using Magick++ library : %s%-13s%s %s('cimg_use_magick' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_magick
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Using FFTW3 library :    %s%-13s%s %s('cimg_use_fftw3' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_fftw3
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      std::fprintf(cimg::output(),"  > Using LAPACK library :   %s%-13s%s %s('cimg_use_lapack' %s)%s\n",
                   cimg::t_bold,
#ifdef cimg_use_lapack
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
#else
                   "No",cimg::t_normal,cimg::t_green,"undefined",
#endif
                   cimg::t_normal);

      cimg_snprintf(tmp,sizeof(tmp),"\"%.1020s\"",cimg::imagemagick_path());
      std::fprintf(cimg::output(),"  > Path of ImageMagick :    %s%-13s%s\n",
                   cimg::t_bold,
                   tmp,
                   cimg::t_normal);

      cimg_snprintf(tmp,sizeof(tmp),"\"%.1020s\"",cimg::graphicsmagick_path());
      std::fprintf(cimg::output(),"  > Path of GraphicsMagick : %s%-13s%s\n",
                   cimg::t_bold,
                   tmp,
                   cimg::t_normal);

      cimg_snprintf(tmp,sizeof(tmp),"\"%.1020s\"",cimg::medcon_path());
      std::fprintf(cimg::output(),"  > Path of 'medcon' :       %s%-13s%s\n",
                   cimg::t_bold,
                   tmp,
                   cimg::t_normal);

      cimg_snprintf(tmp,sizeof(tmp),"\"%.1020s\"",cimg::temporary_path());
      std::fprintf(cimg::output(),"  > Temporary path :         %s%-13s%s\n",
                   cimg::t_bold,
                   tmp,
                   cimg::t_normal);

      std::fprintf(cimg::output(),"\n");
    }

    // Declare LAPACK function signatures if necessary.
#ifdef cimg_use_lapack
    template<typename T>
    inline void getrf(int &N, T *lapA, int *IPIV, int &INFO) {
      dgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
    }

    inline void getrf(int &N, float *lapA, int *IPIV, int &INFO) {
      sgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
    }

    template<typename T>
    inline void getri(int &N, T *lapA, int *IPIV, T* WORK, int &LWORK, int &INFO) {
      dgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
    }

    inline void getri(int &N, float *lapA, int *IPIV, float* WORK, int &LWORK, int &INFO) {
      sgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
    }

    template<typename T>
    inline void gesvd(char &JOB, int &M, int &N, T *lapA, int &MN,
                      T *lapS, T *lapU, T *lapV, T *WORK, int &LWORK, int &INFO) {
      dgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
    }

    inline void gesvd(char &JOB, int &M, int &N, float *lapA, int &MN,
                      float *lapS, float *lapU, float *lapV, float *WORK, int &LWORK, int &INFO) {
      sgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
    }

    template<typename T>
    inline void getrs(char &TRANS, int &N, T *lapA, int *IPIV, T *lapB, int &INFO) {
      int one = 1;
      dgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
    }

    inline void getrs(char &TRANS, int &N, float *lapA, int *IPIV, float *lapB, int &INFO) {
      int one = 1;
      sgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
    }

    template<typename T>
    inline void syev(char &JOB, char &UPLO, int &N, T *lapA, T *lapW, T *WORK, int &LWORK, int &INFO) {
      dsyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
    }

    inline void syev(char &JOB, char &UPLO, int &N, float *lapA, float *lapW, float *WORK, int &LWORK, int &INFO) {
      ssyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
    }
#endif

    // End of the 'cimg' namespace
  }

  /*------------------------------------------------
   #
   #
   #   Definition of mathematical operators and
   #   external functions.
   #
   #
   -------------------------------------------------*/

#define _cimg_create_ext_operators(typ) \
  template<typename T> \
  inline CImg<typename cimg::superset<T,typ>::type> operator+(const typ val, const CImg<T>& img) { \
    return img + val; \
  } \
  template<typename T> \
  inline CImg<typename cimg::superset<T,typ>::type> operator-(const typ val, const CImg<T>& img) { \
    typedef typename cimg::superset<T,typ>::type Tt; \
    return CImg<Tt>(img._width,img._height,img._depth,img._spectrum,val)-=img; \
  } \
  template<typename T> \
  inline CImg<typename cimg::superset<T,typ>::type> operator*(const typ val, const CImg<T>& img) { \
    return img*val; \
  } \
  template<typename T> \
  inline CImg<typename cimg::superset<T,typ>::type> operator/(const typ val, const CImg<T>& img) { \
    return val*img.get_invert(); \
  } \
  template<typename T> \
  inline CImg<typename cimg::superset<T,typ>::type> operator&(const typ val, const CImg<T>& img) { \
    return img & val; \
  } \
  template<typename T> \
  inline CImg<typename cimg::superset<T,typ>::type> operator|(const typ val, const CImg<T>& img) { \
    return img | val; \
  } \
  template<typename T> \
  inline CImg<typename cimg::superset<T,typ>::type> operator^(const typ val, const CImg<T>& img) { \
    return img ^ val; \
  } \

  _cimg_create_ext_operators(bool)
  _cimg_create_ext_operators(unsigned char)
  _cimg_create_ext_operators(char)
  _cimg_create_ext_operators(signed char)
  _cimg_create_ext_operators(unsigned short)
  _cimg_create_ext_operators(short)
  _cimg_create_ext_operators(unsigned int)
  _cimg_create_ext_operators(int)
  _cimg_create_ext_operators(unsigned long)
  _cimg_create_ext_operators(long)
  _cimg_create_ext_operators(float)
  _cimg_create_ext_operators(double)

  template<typename T>
  inline CImg<_cimg_Tfloat> operator+(const char *const expression, const CImg<T>& img) {
    return img + expression;
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> operator-(const char *const expression, const CImg<T>& img) {
    return (CImg<_cimg_Tfloat>(img._width,img._height,img._depth,img._spectrum)=expression)-=img;
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> operator*(const char *const expression, const CImg<T>& img) {
    return img*expression;
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> operator/(const char *const expression, const CImg<T>& img) {
    return expression*img.get_invert();
  }

  template<typename T>
  inline CImg<T> operator&(const char *const expression, const CImg<T>& img) {
    return img & expression;
  }

  template<typename T>
  inline CImg<T> operator|(const char *const expression, const CImg<T>& img) {
    return img | expression;
  }

  template<typename T>
  inline CImg<T> operator^(const char *const expression, const CImg<T>& img) {
    return img ^ expression;
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> sqr(const CImg<T>& instance) {
    return instance.get_sqr();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> sqrt(const CImg<T>& instance) {
    return instance.get_sqrt();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> exp(const CImg<T>& instance) {
    return instance.get_exp();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> log(const CImg<T>& instance) {
    return instance.get_log();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> log10(const CImg<T>& instance) {
    return instance.get_log10();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> abs(const CImg<T>& instance) {
    return instance.get_abs();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> sign(const CImg<T>& instance) {
    return instance.get_sign();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> cos(const CImg<T>& instance) {
    return instance.get_cos();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> sin(const CImg<T>& instance) {
    return instance.get_sin();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> sinc(const CImg<T>& instance) {
    return instance.get_sinc();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> tan(const CImg<T>& instance) {
    return instance.get_tan();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> acos(const CImg<T>& instance) {
    return instance.get_acos();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> asin(const CImg<T>& instance) {
    return instance.get_asin();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> atan(const CImg<T>& instance) {
    return instance.get_atan();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> cosh(const CImg<T>& instance) {
    return instance.get_cosh();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> sinh(const CImg<T>& instance) {
    return instance.get_sinh();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> tanh(const CImg<T>& instance) {
    return instance.get_tanh();
  }

  template<typename T>
  inline CImg<T> transpose(const CImg<T>& instance) {
    return instance.get_transpose();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> invert(const CImg<T>& instance) {
    return instance.get_invert();
  }

  template<typename T>
  inline CImg<_cimg_Tfloat> pseudoinvert(const CImg<T>& instance) {
    return instance.get_pseudoinvert();
  }

  /*-------------------------------------------
   #
   #
   #
   # Definition of the CImgDisplay structure
   #
   #
   #
   --------------------------------------------*/

  //! This class represents a window which can display \c CImg<T> images and handles mouse and keyboard events.
  /**
     Creating a \c CImgDisplay instance opens a window that can be used to display a \c CImg<T> image
     of a \c CImgList<T> image list inside. When a display is created, associated window events
     (such as mouse motion, keyboard and window size changes) are handled and can be easily
     detected by testing specific \c CImgDisplay data fields.
     See \ref cimg_displays for a complete tutorial on using the \c CImgDisplay class.
  **/

  struct CImgDisplay {

    //! Width of the display.
    unsigned int _width;

    //! Height of the display.
    unsigned int _height;

    //! Width of the underlying window.
    volatile unsigned int _window_width;

    //! Height of the underlying window.
    volatile unsigned int _window_height;

    //! X-pos of the display on the screen.
    volatile int _window_x;

    //! Y-pos of the display on the screen.
    volatile int _window_y;

    //! X-coordinate of the mouse pointer on the display.
    volatile int _mouse_x;

    //! Y-coordinate of the mouse pointer on the display.
    volatile int _mouse_y;

    //! Normalization type used for the display.
    unsigned int _normalization;

    //! Display title.
    char *_title;

    //! Button state of the mouse.
    volatile unsigned int _button;

    //! Wheel state of the mouse.
    volatile int _wheel;

    //! Key value if pressed.
    volatile unsigned int _keys[128];
    volatile unsigned int _released_keys[128];

    //! Closed state of the window.
    volatile bool _is_closed;

    //! Resized state of the window.
    volatile bool _is_resized;

    //! Moved state of the window.
    volatile bool _is_moved;

    //! Event state of the window.
    volatile bool _is_event;

    //! Current state of the corresponding key (exists for all referenced keys).
    volatile bool _is_keyESC;
    volatile bool _is_keyF1;
    volatile bool _is_keyF2;
    volatile bool _is_keyF3;
    volatile bool _is_keyF4;
    volatile bool _is_keyF5;
    volatile bool _is_keyF6;
    volatile bool _is_keyF7;
    volatile bool _is_keyF8;
    volatile bool _is_keyF9;
    volatile bool _is_keyF10;
    volatile bool _is_keyF11;
    volatile bool _is_keyF12;
    volatile bool _is_keyPAUSE;
    volatile bool _is_key1;
    volatile bool _is_key2;
    volatile bool _is_key3;
    volatile bool _is_key4;
    volatile bool _is_key5;
    volatile bool _is_key6;
    volatile bool _is_key7;
    volatile bool _is_key8;
    volatile bool _is_key9;
    volatile bool _is_key0;
    volatile bool _is_keyBACKSPACE;
    volatile bool _is_keyINSERT;
    volatile bool _is_keyHOME;
    volatile bool _is_keyPAGEUP;
    volatile bool _is_keyTAB;
    volatile bool _is_keyQ;
    volatile bool _is_keyW;
    volatile bool _is_keyE;
    volatile bool _is_keyR;
    volatile bool _is_keyT;
    volatile bool _is_keyY;
    volatile bool _is_keyU;
    volatile bool _is_keyI;
    volatile bool _is_keyO;
    volatile bool _is_keyP;
    volatile bool _is_keyDELETE;
    volatile bool _is_keyEND;
    volatile bool _is_keyPAGEDOWN;
    volatile bool _is_keyCAPSLOCK;
    volatile bool _is_keyA;
    volatile bool _is_keyS;
    volatile bool _is_keyD;
    volatile bool _is_keyF;
    volatile bool _is_keyG;
    volatile bool _is_keyH;
    volatile bool _is_keyJ;
    volatile bool _is_keyK;
    volatile bool _is_keyL;
    volatile bool _is_keyENTER;
    volatile bool _is_keySHIFTLEFT;
    volatile bool _is_keyZ;
    volatile bool _is_keyX;
    volatile bool _is_keyC;
    volatile bool _is_keyV;
    volatile bool _is_keyB;
    volatile bool _is_keyN;
    volatile bool _is_keyM;
    volatile bool _is_keySHIFTRIGHT;
    volatile bool _is_keyARROWUP;
    volatile bool _is_keyCTRLLEFT;
    volatile bool _is_keyAPPLEFT;
    volatile bool _is_keyALT;
    volatile bool _is_keySPACE;
    volatile bool _is_keyALTGR;
    volatile bool _is_keyAPPRIGHT;
    volatile bool _is_keyMENU;
    volatile bool _is_keyCTRLRIGHT;
    volatile bool _is_keyARROWLEFT;
    volatile bool _is_keyARROWDOWN;
    volatile bool _is_keyARROWRIGHT;
    volatile bool _is_keyPAD0;
    volatile bool _is_keyPAD1;
    volatile bool _is_keyPAD2;
    volatile bool _is_keyPAD3;
    volatile bool _is_keyPAD4;
    volatile bool _is_keyPAD5;
    volatile bool _is_keyPAD6;
    volatile bool _is_keyPAD7;
    volatile bool _is_keyPAD8;
    volatile bool _is_keyPAD9;
    volatile bool _is_keyPADADD;
    volatile bool _is_keyPADSUB;
    volatile bool _is_keyPADMUL;
    volatile bool _is_keyPADDIV;

    //! Fullscreen state of the display.
    bool _is_fullscreen;

    // Internal variables.
    float _fps_fps, _min, _max;
    unsigned long _timer, _fps_frames, _fps_timer;

    //@}
    //---------------------------
    //
    //! \name Plugins
    //@{
    //---------------------------

#ifdef cimgdisplay_plugin
#include cimgdisplay_plugin
#endif
#ifdef cimgdisplay_plugin1
#include cimgdisplay_plugin1
#endif
#ifdef cimgdisplay_plugin2
#include cimgdisplay_plugin2
#endif
#ifdef cimgdisplay_plugin3
#include cimgdisplay_plugin3
#endif
#ifdef cimgdisplay_plugin4
#include cimgdisplay_plugin4
#endif
#ifdef cimgdisplay_plugin5
#include cimgdisplay_plugin5
#endif
#ifdef cimgdisplay_plugin6
#include cimgdisplay_plugin6
#endif
#ifdef cimgdisplay_plugin7
#include cimgdisplay_plugin7
#endif
#ifdef cimgdisplay_plugin8
#include cimgdisplay_plugin8
#endif

    //@}
    //--------------------------------------------------------
    //
    //! \name Constructors / Destructor / Instance Management
    //@{
    //--------------------------------------------------------

    //! Destructor.
    ~CImgDisplay() {
      assign();
    }

    //! Create an empty display window.
    CImgDisplay():
      _width(0),_height(0),_window_width(0),_window_height(0),_window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),
      _normalization(0),_title(0),_button(0),_wheel(0),_is_closed(true),_is_resized(false),_is_moved(false),_is_event(false),
      _is_fullscreen(false),_min(0),_max(0) {
      assign();
    }

    //! Create a display window with a specified size \p pwidth x \p height.
    /** \param width : Width of the display window.
        \param height : Height of the display window.
        \param title : Title of the display window.
        \param normalization : Normalization type of the display window (0=none, 1=always, 2=once).
        \param is_fullscreen : Fullscreen mode.
        \param is_closed : Initially visible mode.
        A black image will be initially displayed in the display window.
    **/
    CImgDisplay(const unsigned int width, const unsigned int height,
                const char *const title=0, const unsigned int normalization=3,
                const bool is_fullscreen=false, const bool is_closed=false):
      _width(0),_height(0),_window_width(0),_window_height(0),_window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),
      _normalization(0),_title(0),_button(0),_wheel(0),_is_closed(true),_is_resized(false),_is_moved(false),_is_event(false),
      _is_fullscreen(false),_min(0),_max(0) {
      assign(width,height,title,normalization,is_fullscreen,is_closed);
    }

    //! Create a display window from an image.
    /** \param img : Image that will be used to create the display window.
        \param title : Title of the display window
        \param normalization : Normalization type of the display window.
        \param is_fullscreen : Fullscreen mode.
        \param is_closed : Initially visible mode.
    **/
    template<typename T>
    explicit CImgDisplay(const CImg<T>& img,
                         const char *const title=0, const unsigned int normalization=3,
                         const bool is_fullscreen=false, const bool is_closed=false):
      _width(0),_height(0),_window_width(0),_window_height(0),_window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),
      _normalization(0),_title(0),_button(0),_wheel(0),_is_closed(true),_is_resized(false),_is_moved(false),_is_event(false),
      _is_fullscreen(false),_min(0),_max(0) {
      assign(img,title,normalization,is_fullscreen,is_closed);
    }

    //! Create a display window from an image list.
    /** \param list : The list of images to display.
        \param title : Title of the display window
        \param normalization : Normalization type of the display window.
        \param is_fullscreen : Fullscreen mode.
        \param is_closed : Initially visible mode.
    **/
    template<typename T>
    explicit CImgDisplay(const CImgList<T>& list,
                         const char *const title=0, const unsigned int normalization=3,
                         const bool is_fullscreen=false, const bool is_closed=false):
      _width(0),_height(0),_window_width(0),_window_height(0),_window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),
      _normalization(0),_title(0),_button(0),_wheel(0),_is_closed(true),_is_resized(false),_is_moved(false),_is_event(false),
      _is_fullscreen(false),_min(0),_max(0) {
      assign(list,title,normalization,is_fullscreen,is_closed);
    }

    //! Create a display window by copying another one.
    /**
        \param disp  : Display window to copy.
    **/
    CImgDisplay(const CImgDisplay& disp):
      _width(0),_height(0),_window_width(0),_window_height(0),_window_x(0),_window_y(0),_mouse_x(-1),_mouse_y(-1),
      _normalization(0),_title(0),_button(0),_wheel(0),_is_closed(true),_is_resized(false),_is_moved(false),_is_event(false),
      _is_fullscreen(false),_min(0),_max(0) {
      assign(disp);
    }

#if cimg_display==0

    static void _no_display_exception() {
      throw CImgDisplayException("CImgDisplay() : No display available.");
    }

    //! In-place version of the destructor.
    CImgDisplay& assign() {
      _no_display_exception();
      return flush();
    }

    //! In-place version of the constructor.
    CImgDisplay& assign(const unsigned int width, const unsigned int height,
                        const char *const title=0, const unsigned int normalization=3,
                        const bool is_fullscreen=false, const bool is_closed=false) {
      cimg::unused(width,height,title,normalization,is_fullscreen,is_closed);
      return assign();
    }

    //! In-place version of the constructor.
    template<typename T>
    CImgDisplay& assign(const CImg<T>& img,
                        const char *const title=0, const unsigned int normalization=3,
                        const bool is_fullscreen=false, const bool is_closed=false) {
      return assign(img._width,img._height,title,normalization,is_fullscreen,is_closed);
    }

    //! In-place version of the constructor.
    template<typename T>
    CImgDisplay& assign(const CImgList<T>& list,
                        const char *const title=0, const unsigned int normalization=3,
                        const bool is_fullscreen=false, const bool is_closed=false) {
      return assign(list._width,list._width,title,normalization,is_fullscreen,is_closed);
    }

    //! In-place version of the constructor.
    CImgDisplay& assign(const CImgDisplay &disp) {
      return assign(disp._width,disp._height);
    }

#endif

    //! Get a reference to an empty display.
    static CImgDisplay& empty() {
      static CImgDisplay _empty;
      return _empty.assign();
    }

#define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false),CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true)
    static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy, const unsigned int dz,
                                   const int dmin, const int dmax,const bool return_y) {
      unsigned int nw = dx + (dz>1?dz:0), nh = dy + (dz>1?dz:0);
      const unsigned int
        sw = CImgDisplay::screen_width(), sh = CImgDisplay::screen_height(),
        mw = dmin<0?(unsigned int)(sw*-dmin/100):(unsigned int)dmin,
        mh = dmin<0?(unsigned int)(sh*-dmin/100):(unsigned int)dmin,
        Mw = dmax<0?(unsigned int)(sw*-dmax/100):(unsigned int)dmax,
        Mh = dmax<0?(unsigned int)(sh*-dmax/100):(unsigned int)dmax;
      if (nw<mw) { nh = nh*mw/nw; nh+=(nh==0?1:0); nw = mw; }
      if (nh<mh) { nw = nw*mh/nh; nw+=(nw==0?1:0); nh = mh; }
      if (nw>Mw) { nh = nh*Mw/nw; nh+=(nh==0?1:0); nw = Mw; }
      if (nh>Mh) { nw = nw*Mh/nh; nw+=(nw==0?1:0); nh = Mh; }
      if (nw<mw) nw = mw;
      if (nh<mh) nh = mh;
      return return_y?nh:nw;
    }

    //@}
    //------------------------------------------
    //
    //! \name Overloaded Operators
    //@{
    //------------------------------------------

    // Operator=().
    template<typename t>
    CImgDisplay& operator=(const CImg<t>& img) {
      return display(img);
    }

    // Operator=().
    template<typename t>
    CImgDisplay& operator=(const CImgList<t>& list) {
      return display(list);
    }

    //! Operator=().
    CImgDisplay& operator=(const CImgDisplay& disp) {
      return assign(disp);
    }

    //! Return true if display is not empty.
    operator bool() const {
      return !is_empty();
    }

    //@}
    //------------------------------------------
    //
    //! \name Instance Checking
    //@{
    //------------------------------------------

    //! Return true is display is empty.
    bool is_empty() const {
      return !(_width && _height);
    }

    bool is_closed() const {
      return _is_closed;
    }

    bool is_resized() const {
      return _is_resized;
    }

    bool is_moved() const {
      return _is_moved;
    }

    bool is_event() const {
      return _is_event;
    }

    bool is_fullscreen() const {
      return _is_fullscreen;
    }

    bool is_key() const {
      return _is_keyESC || _is_keyF1 || _is_keyF2 || _is_keyF3 ||
        _is_keyF4 || _is_keyF5 || _is_keyF6 || _is_keyF7 ||
        _is_keyF8 || _is_keyF9 || _is_keyF10 || _is_keyF11 ||
        _is_keyF12 || _is_keyPAUSE || _is_key1 || _is_key2 ||
        _is_key3 || _is_key4 || _is_key5 || _is_key6 ||
        _is_key7 || _is_key8 || _is_key9 || _is_key0 ||
        _is_keyBACKSPACE || _is_keyINSERT || _is_keyHOME ||
        _is_keyPAGEUP || _is_keyTAB || _is_keyQ || _is_keyW ||
        _is_keyE || _is_keyR || _is_keyT || _is_keyY ||
        _is_keyU || _is_keyI || _is_keyO || _is_keyP ||
        _is_keyDELETE || _is_keyEND || _is_keyPAGEDOWN ||
        _is_keyCAPSLOCK || _is_keyA || _is_keyS || _is_keyD ||
        _is_keyF || _is_keyG || _is_keyH || _is_keyJ ||
        _is_keyK || _is_keyL || _is_keyENTER ||
        _is_keySHIFTLEFT || _is_keyZ || _is_keyX || _is_keyC ||
        _is_keyV || _is_keyB || _is_keyN || _is_keyM ||
        _is_keySHIFTRIGHT || _is_keyARROWUP || _is_keyCTRLLEFT ||
        _is_keyAPPLEFT || _is_keyALT || _is_keySPACE || _is_keyALTGR ||
        _is_keyAPPRIGHT || _is_keyMENU || _is_keyCTRLRIGHT ||
        _is_keyARROWLEFT || _is_keyARROWDOWN || _is_keyARROWRIGHT ||
        _is_keyPAD0 || _is_keyPAD1 || _is_keyPAD2 ||
        _is_keyPAD3 || _is_keyPAD4 || _is_keyPAD5 ||
        _is_keyPAD6 || _is_keyPAD7 || _is_keyPAD8 ||
        _is_keyPAD9 || _is_keyPADADD || _is_keyPADSUB ||
        _is_keyPADMUL || _is_keyPADDIV;
    }

#define _cimg_iskey_def(k) \
    bool is_key##k() const { \
      return _is_key##k; \
    }
    _cimg_iskey_def(ESC); _cimg_iskey_def(F1); _cimg_iskey_def(F2); _cimg_iskey_def(F3);
    _cimg_iskey_def(F4); _cimg_iskey_def(F5); _cimg_iskey_def(F6); _cimg_iskey_def(F7);
    _cimg_iskey_def(F8); _cimg_iskey_def(F9); _cimg_iskey_def(F10); _cimg_iskey_def(F11);
    _cimg_iskey_def(F12); _cimg_iskey_def(PAUSE); _cimg_iskey_def(1); _cimg_iskey_def(2);
    _cimg_iskey_def(3); _cimg_iskey_def(4); _cimg_iskey_def(5); _cimg_iskey_def(6);
    _cimg_iskey_def(7); _cimg_iskey_def(8); _cimg_iskey_def(9); _cimg_iskey_def(0);
    _cimg_iskey_def(BACKSPACE); _cimg_iskey_def(INSERT); _cimg_iskey_def(HOME);
    _cimg_iskey_def(PAGEUP); _cimg_iskey_def(TAB); _cimg_iskey_def(Q); _cimg_iskey_def(W);
    _cimg_iskey_def(E); _cimg_iskey_def(R); _cimg_iskey_def(T); _cimg_iskey_def(Y);
    _cimg_iskey_def(U); _cimg_iskey_def(I); _cimg_iskey_def(O); _cimg_iskey_def(P);
    _cimg_iskey_def(DELETE); _cimg_iskey_def(END); _cimg_iskey_def(PAGEDOWN);
    _cimg_iskey_def(CAPSLOCK); _cimg_iskey_def(A); _cimg_iskey_def(S); _cimg_iskey_def(D);
    _cimg_iskey_def(F); _cimg_iskey_def(G); _cimg_iskey_def(H); _cimg_iskey_def(J);
    _cimg_iskey_def(K); _cimg_iskey_def(L); _cimg_iskey_def(ENTER);
    _cimg_iskey_def(SHIFTLEFT); _cimg_iskey_def(Z); _cimg_iskey_def(X); _cimg_iskey_def(C);
    _cimg_iskey_def(V); _cimg_iskey_def(B); _cimg_iskey_def(N); _cimg_iskey_def(M);
    _cimg_iskey_def(SHIFTRIGHT); _cimg_iskey_def(ARROWUP); _cimg_iskey_def(CTRLLEFT);
    _cimg_iskey_def(APPLEFT); _cimg_iskey_def(ALT); _cimg_iskey_def(SPACE); _cimg_iskey_def(ALTGR);
    _cimg_iskey_def(APPRIGHT); _cimg_iskey_def(MENU); _cimg_iskey_def(CTRLRIGHT);
    _cimg_iskey_def(ARROWLEFT); _cimg_iskey_def(ARROWDOWN); _cimg_iskey_def(ARROWRIGHT);
    _cimg_iskey_def(PAD0); _cimg_iskey_def(PAD1); _cimg_iskey_def(PAD2);
    _cimg_iskey_def(PAD3); _cimg_iskey_def(PAD4); _cimg_iskey_def(PAD5);
    _cimg_iskey_def(PAD6); _cimg_iskey_def(PAD7); _cimg_iskey_def(PAD8);
    _cimg_iskey_def(PAD9); _cimg_iskey_def(PADADD); _cimg_iskey_def(PADSUB);
    _cimg_iskey_def(PADMUL); _cimg_iskey_def(PADDIV);

    bool is_key(const unsigned int key) const {
#define _cimg_iskey_test(k) if (key==cimg::key##k) return _is_key##k;
      _cimg_iskey_test(ESC); _cimg_iskey_test(F1); _cimg_iskey_test(F2); _cimg_iskey_test(F3);
      _cimg_iskey_test(F4); _cimg_iskey_test(F5); _cimg_iskey_test(F6); _cimg_iskey_test(F7);
      _cimg_iskey_test(F8); _cimg_iskey_test(F9); _cimg_iskey_test(F10); _cimg_iskey_test(F11);
      _cimg_iskey_test(F12); _cimg_iskey_test(PAUSE); _cimg_iskey_test(1); _cimg_iskey_test(2);
      _cimg_iskey_test(3); _cimg_iskey_test(4); _cimg_iskey_test(5); _cimg_iskey_test(6);
      _cimg_iskey_test(7); _cimg_iskey_test(8); _cimg_iskey_test(9); _cimg_iskey_test(0);
      _cimg_iskey_test(BACKSPACE); _cimg_iskey_test(INSERT); _cimg_iskey_test(HOME);
      _cimg_iskey_test(PAGEUP); _cimg_iskey_test(TAB); _cimg_iskey_test(Q); _cimg_iskey_test(W);
      _cimg_iskey_test(E); _cimg_iskey_test(R); _cimg_iskey_test(T); _cimg_iskey_test(Y);
      _cimg_iskey_test(U); _cimg_iskey_test(I); _cimg_iskey_test(O); _cimg_iskey_test(P);
      _cimg_iskey_test(DELETE); _cimg_iskey_test(END); _cimg_iskey_test(PAGEDOWN);
      _cimg_iskey_test(CAPSLOCK); _cimg_iskey_test(A); _cimg_iskey_test(S); _cimg_iskey_test(D);
      _cimg_iskey_test(F); _cimg_iskey_test(G); _cimg_iskey_test(H); _cimg_iskey_test(J);
      _cimg_iskey_test(K); _cimg_iskey_test(L); _cimg_iskey_test(ENTER);
      _cimg_iskey_test(SHIFTLEFT); _cimg_iskey_test(Z); _cimg_iskey_test(X); _cimg_iskey_test(C);
      _cimg_iskey_test(V); _cimg_iskey_test(B); _cimg_iskey_test(N); _cimg_iskey_test(M);
      _cimg_iskey_test(SHIFTRIGHT); _cimg_iskey_test(ARROWUP); _cimg_iskey_test(CTRLLEFT);
      _cimg_iskey_test(APPLEFT); _cimg_iskey_test(ALT); _cimg_iskey_test(SPACE); _cimg_iskey_test(ALTGR);
      _cimg_iskey_test(APPRIGHT); _cimg_iskey_test(MENU); _cimg_iskey_test(CTRLRIGHT);
      _cimg_iskey_test(ARROWLEFT); _cimg_iskey_test(ARROWDOWN); _cimg_iskey_test(ARROWRIGHT);
      _cimg_iskey_test(PAD0); _cimg_iskey_test(PAD1); _cimg_iskey_test(PAD2);
      _cimg_iskey_test(PAD3); _cimg_iskey_test(PAD4); _cimg_iskey_test(PAD5);
      _cimg_iskey_test(PAD6); _cimg_iskey_test(PAD7); _cimg_iskey_test(PAD8);
      _cimg_iskey_test(PAD9); _cimg_iskey_test(PADADD); _cimg_iskey_test(PADSUB);
      _cimg_iskey_test(PADMUL); _cimg_iskey_test(PADDIV);
      return false;
    }

    //! Get keycode corresponding to given input string.
    bool is_key(const char *const textcode) const {
#define _cimg_iskey_test2(k) if (!cimg::strcasecmp(textcode,#k)) return _is_key##k;
      _cimg_iskey_test2(ESC); _cimg_iskey_test2(F1); _cimg_iskey_test2(F2); _cimg_iskey_test2(F3);
      _cimg_iskey_test2(F4); _cimg_iskey_test2(F5); _cimg_iskey_test2(F6); _cimg_iskey_test2(F7);
      _cimg_iskey_test2(F8); _cimg_iskey_test2(F9); _cimg_iskey_test2(F10); _cimg_iskey_test2(F11);
      _cimg_iskey_test2(F12); _cimg_iskey_test2(PAUSE); _cimg_iskey_test2(1); _cimg_iskey_test2(2);
      _cimg_iskey_test2(3); _cimg_iskey_test2(4); _cimg_iskey_test2(5); _cimg_iskey_test2(6);
      _cimg_iskey_test2(7); _cimg_iskey_test2(8); _cimg_iskey_test2(9); _cimg_iskey_test2(0);
      _cimg_iskey_test2(BACKSPACE); _cimg_iskey_test2(INSERT); _cimg_iskey_test2(HOME);
      _cimg_iskey_test2(PAGEUP); _cimg_iskey_test2(TAB); _cimg_iskey_test2(Q); _cimg_iskey_test2(W);
      _cimg_iskey_test2(E); _cimg_iskey_test2(R); _cimg_iskey_test2(T); _cimg_iskey_test2(Y);
      _cimg_iskey_test2(U); _cimg_iskey_test2(I); _cimg_iskey_test2(O); _cimg_iskey_test2(P);
      _cimg_iskey_test2(DELETE); _cimg_iskey_test2(END); _cimg_iskey_test2(PAGEDOWN);
      _cimg_iskey_test2(CAPSLOCK); _cimg_iskey_test2(A); _cimg_iskey_test2(S); _cimg_iskey_test2(D);
      _cimg_iskey_test2(F); _cimg_iskey_test2(G); _cimg_iskey_test2(H); _cimg_iskey_test2(J);
      _cimg_iskey_test2(K); _cimg_iskey_test2(L); _cimg_iskey_test2(ENTER);
      _cimg_iskey_test2(SHIFTLEFT); _cimg_iskey_test2(Z); _cimg_iskey_test2(X); _cimg_iskey_test2(C);
      _cimg_iskey_test2(V); _cimg_iskey_test2(B); _cimg_iskey_test2(N); _cimg_iskey_test2(M);
      _cimg_iskey_test2(SHIFTRIGHT); _cimg_iskey_test2(ARROWUP); _cimg_iskey_test2(CTRLLEFT);
      _cimg_iskey_test2(APPLEFT); _cimg_iskey_test2(ALT); _cimg_iskey_test2(SPACE); _cimg_iskey_test2(ALTGR);
      _cimg_iskey_test2(APPRIGHT); _cimg_iskey_test2(MENU); _cimg_iskey_test2(CTRLRIGHT);
      _cimg_iskey_test2(ARROWLEFT); _cimg_iskey_test2(ARROWDOWN); _cimg_iskey_test2(ARROWRIGHT);
      _cimg_iskey_test2(PAD0); _cimg_iskey_test2(PAD1); _cimg_iskey_test2(PAD2);
      _cimg_iskey_test2(PAD3); _cimg_iskey_test2(PAD4); _cimg_iskey_test2(PAD5);
      _cimg_iskey_test2(PAD6); _cimg_iskey_test2(PAD7); _cimg_iskey_test2(PAD8);
      _cimg_iskey_test2(PAD9); _cimg_iskey_test2(PADADD); _cimg_iskey_test2(PADSUB);
      _cimg_iskey_test2(PADMUL); _cimg_iskey_test2(PADDIV);
      return false;
    }

    //! Test if a key sequence has been typed.
    bool is_key_sequence(const unsigned int *const key_sequence, const unsigned int length, const bool remove_sequence=false) {
      if (key_sequence && length) {
        const unsigned int
          *const ps_end = key_sequence + length - 1,
          *const pk_end = (unsigned int*)_keys + 1 + sizeof(_keys)/sizeof(unsigned int) - length,
          k = *ps_end;
        for (unsigned int *pk = (unsigned int*)_keys; pk<pk_end; ) {
          if (*(pk++)==k) {
            bool res = true;
            const unsigned int *ps = ps_end, *pk2 = pk;
            for (unsigned int i = 1; i<length; ++i) res = (*(--ps)==*(pk2++));
            if (res) {
              if (remove_sequence) std::memset((void*)(pk-1),0,sizeof(unsigned int)*length);
              return true;
            }
          }
        }
      }
      return false;
    }

    //@}
    //------------------------------------------
    //
    //! \name Instance Characteristics
    //@{
    //------------------------------------------

    //! Get display width.
    int width() const {
      return (int)_width;
    }

    //! Get display height.
    int height() const {
      return (int)_height;
    }

    //! Get X-coordinate of the mouse pointer.
    int mouse_x() const {
      return _mouse_x;
    }

    //! Get Y-coordinate of the mouse pointer.
    int mouse_y() const {
      return _mouse_y;
    }

    //! Get current or previous state of the mouse buttons.
    unsigned int button() const {
      return _button;
    }

    //! Get current state of the mouse wheel.
    int wheel() const {
      return _wheel;
    }

    //! Get current or previous state of the keyboard.
    unsigned int key(const unsigned int pos=0) const {
      return pos<(sizeof(_keys)/sizeof(unsigned int))?_keys[pos]:0;
    }

    unsigned int released_key(const unsigned int pos=0) const {
      return pos<(sizeof(_released_keys)/sizeof(unsigned int))?_released_keys[pos]:0;
    }

    //! Get keycode corresponding to given input string.
    static unsigned int keycode(const char *const textcode) {
#define _cimg_keycode(k) if (!cimg::strcasecmp(textcode,#k)) return cimg::key##k;
      _cimg_keycode(ESC); _cimg_keycode(F1); _cimg_keycode(F2); _cimg_keycode(F3);
      _cimg_keycode(F4); _cimg_keycode(F5); _cimg_keycode(F6); _cimg_keycode(F7);
      _cimg_keycode(F8); _cimg_keycode(F9); _cimg_keycode(F10); _cimg_keycode(F11);
      _cimg_keycode(F12); _cimg_keycode(PAUSE); _cimg_keycode(1); _cimg_keycode(2);
      _cimg_keycode(3); _cimg_keycode(4); _cimg_keycode(5); _cimg_keycode(6);
      _cimg_keycode(7); _cimg_keycode(8); _cimg_keycode(9); _cimg_keycode(0);
      _cimg_keycode(BACKSPACE); _cimg_keycode(INSERT); _cimg_keycode(HOME);
      _cimg_keycode(PAGEUP); _cimg_keycode(TAB); _cimg_keycode(Q); _cimg_keycode(W);
      _cimg_keycode(E); _cimg_keycode(R); _cimg_keycode(T); _cimg_keycode(Y);
      _cimg_keycode(U); _cimg_keycode(I); _cimg_keycode(O); _cimg_keycode(P);
      _cimg_keycode(DELETE); _cimg_keycode(END); _cimg_keycode(PAGEDOWN);
      _cimg_keycode(CAPSLOCK); _cimg_keycode(A); _cimg_keycode(S); _cimg_keycode(D);
      _cimg_keycode(F); _cimg_keycode(G); _cimg_keycode(H); _cimg_keycode(J);
      _cimg_keycode(K); _cimg_keycode(L); _cimg_keycode(ENTER);
      _cimg_keycode(SHIFTLEFT); _cimg_keycode(Z); _cimg_keycode(X); _cimg_keycode(C);
      _cimg_keycode(V); _cimg_keycode(B); _cimg_keycode(N); _cimg_keycode(M);
      _cimg_keycode(SHIFTRIGHT); _cimg_keycode(ARROWUP); _cimg_keycode(CTRLLEFT);
      _cimg_keycode(APPLEFT); _cimg_keycode(ALT); _cimg_keycode(SPACE); _cimg_keycode(ALTGR);
      _cimg_keycode(APPRIGHT); _cimg_keycode(MENU); _cimg_keycode(CTRLRIGHT);
      _cimg_keycode(ARROWLEFT); _cimg_keycode(ARROWDOWN); _cimg_keycode(ARROWRIGHT);
      _cimg_keycode(PAD0); _cimg_keycode(PAD1); _cimg_keycode(PAD2);
      _cimg_keycode(PAD3); _cimg_keycode(PAD4); _cimg_keycode(PAD5);
      _cimg_keycode(PAD6); _cimg_keycode(PAD7); _cimg_keycode(PAD8);
      _cimg_keycode(PAD9); _cimg_keycode(PADADD); _cimg_keycode(PADSUB);
      _cimg_keycode(PADMUL); _cimg_keycode(PADDIV);
      return 0;
    }

    //! Get normalization type of the display.
    unsigned int normalization() const {
      return _normalization;
    }

    //! Get title of the display.
    const char *title() const {
      return _title;
    }

    //! Get display window width.
    int window_width() const {
      return (int)_window_width;
    }

    //! Get display window height.
    int window_height() const {
      return (int)_window_height;
    }

    //! Get X-coordinate of the window.
    int window_x() const {
      return _window_x;
    }

    //! Get Y-coordinate of the window.
    int window_y() const {
      return _window_y;
    }

#if cimg_display==0

    //! Get the width of the screen resolution.
    static int screen_width() {
      _no_display_exception();
      return 0;
    }

    //! Get the height of the screen resolution.
    static int screen_height() {
      _no_display_exception();
      return 0;
    }

#endif

    //! Get the frame per second rate.
    float frames_per_second() {
      if (!_fps_timer) _fps_timer = cimg::time();
      const float delta = (cimg::time()-_fps_timer)/1000.0f;
      ++_fps_frames;
      if (delta>=1) {
        _fps_fps = _fps_frames/delta;
        _fps_frames = 0;
        _fps_timer = cimg::time();
      }
      return _fps_fps;
    }

    //@}
    //------------------------------------------
    //
    //! \name Display Manipulation
    //@{
    //------------------------------------------

#if cimg_display==0

    //! Display an image in a window.
    template<typename T>
    CImgDisplay& display(const CImg<T>& img) {
      return assign(img);
    }

#endif

    //! Display an image list CImgList<T> into a display window.
    /** First, all images of the list are appended into a single image used for visualization,
        then this image is displayed in the current display window.
        \param list : The list of images to display.
        \param axis : The axis used to append the image for visualization. Can be 'x' (default),'y','z' or 'c'.
        \param align : Defines the relative alignment of images when displaying images of different sizes.
        Can be '\p c' (centered, which is the default), '\p p' (top alignment) and '\p n' (bottom aligment).
    **/
    template<typename T>
    CImgDisplay& display(const CImgList<T>& list, const char axis='x', const float align=0) {
      return display(list.get_append(axis,align));
    }

    //! Resize a display window in its current size.
    CImgDisplay& resize(const bool force_redraw=true) {
      resize(_window_width,_window_height,force_redraw);
      return *this;
    }

    //! Resize a display window with the size of an image.
    /** \param img    : Input image. \p image.width and \p image.height give the new dimensions of the display window.
        \param force_redraw : If \p true (default), the current displayed image in the display window will
        be bloc-interpolated to fit the new dimensions. If \p false, a black image will be drawn in the resized window.
    **/
    template<typename T>
    CImgDisplay& resize(const CImg<T>& img, const bool force_redraw=true) {
      return resize(img._width,img._height,force_redraw);
    }

    //! Resize a display window using the size of the given display \p disp.
    CImgDisplay& resize(const CImgDisplay& disp, const bool force_redraw=true) {
      return resize(disp._width,disp._height,force_redraw);
    }

#if cimg_display==0

    //! Resize window.
    CImgDisplay& resize(const int width, const int height, const bool force_redraw=true) {
      return assign(width,height,0,3,force_redraw);
    }

#endif

    // Render pixel buffer with size (wd,hd) from source buffer of size (ws,hs).
    template<typename t, typename T>
    static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs,
                               t *ptrd, const unsigned int wd, const unsigned int hd) {
      unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd+1], *poffx, *poffy;
      float s, curr, old;
      s = (float)ws/wd;
      poffx = offx; curr = 0; for (unsigned int x = 0; x<wd; ++x) { old = curr; curr+=s; *(poffx++) = (unsigned int)curr - (unsigned int)old; }
      s = (float)hs/hd;
      poffy = offy; curr = 0; for (unsigned int y = 0; y<hd; ++y) { old = curr; curr+=s; *(poffy++) = ws*((unsigned int)curr - (unsigned int)old); }
      *poffy = 0;
      poffy = offy;
      for (unsigned int y = 0; y<hd; ) {
        const T *ptr = ptrs;
        poffx = offx;
        for (unsigned int x = 0; x<wd; ++x) { *(ptrd++) = *ptr; ptr+=*(poffx++); }
        ++y;
        unsigned int dy = *(poffy++);
        for ( ; !dy && y<hd; std::memcpy(ptrd,ptrd - wd,sizeof(t)*wd), ++y, ptrd+=wd, dy = *(poffy++)) {}
        ptrs+=dy;
      }
      delete[] offx; delete[] offy;
    }

    //! Set fullscreen mode.
    CImgDisplay& set_fullscreen(const bool is_fullscreen, const bool force_redraw=true) {
      if (is_empty() || _is_fullscreen==is_fullscreen) return *this;
      return toggle_fullscreen(force_redraw);
    }

#if cimg_display==0

    //! Toggle fullscreen mode.
    CImgDisplay& toggle_fullscreen(const bool force_redraw=true) {
      return assign(_width,_height,0,3,force_redraw);
    }

    //! Show a closed display.
    CImgDisplay& show() {
      return assign();
    }

    //! Close a visible display.
    CImgDisplay& close() {
      return assign();
    }

    //! Move window.
    CImgDisplay& move(const int pos_x, const int pos_y) {
      return assign(pos_x,pos_y);
    }

    //! Show mouse pointer.
    CImgDisplay& show_mouse() {
      return assign();
    }

    //! Hide mouse pointer.
    CImgDisplay& hide_mouse() {
      return assign();
    }

    //! Move mouse pointer to a specific location.
    CImgDisplay& set_mouse(const int pos_x, const int pos_y) {
      return assign(pos_x,pos_y);
    }

    CImgDisplay& set_title(const char *const format, ...) {
      return assign(0,0,format);
    }

    //! Render image buffer into GDI native image format.
    template<typename T>
    CImgDisplay& render(const CImg<T>& img) {
      return assign(img);
    }

    //! Re-paint image content in window.
    CImgDisplay& paint() {
      return assign();
    }

    //! Take a snapshot of the display in the specified image.
    template<typename T>
    const CImgDisplay& snapshot(CImg<T>& img) const {
      _no_display_exception();
      return *this;
    }
#endif

    //! Simulate a mouse button event.
    CImgDisplay& set_button() {
      _button = 0;
      _is_event = true;
      return *this;
    }

    CImgDisplay& set_button(const unsigned int button, const bool is_pressed=true) {
      const unsigned int buttoncode = button==1?1:button==2?2:button==3?4:0;
      if (is_pressed) _button |= buttoncode; else _button &= ~buttoncode;
      _is_event = buttoncode?true:false;
      return *this;
    }

    //! Simulate a mouse wheel event, or flush wheel events.
    CImgDisplay& set_wheel() {
      _wheel = 0;
      _is_event = true;
      return *this;
    }

    CImgDisplay& set_wheel(const int amplitude) {
      _wheel+=amplitude;
      _is_event = amplitude?true:false;
      return *this;
    }

    //! Simulate a keyboard press/release event, or flush all key events.
    CImgDisplay& set_key() {
      std::memset((void*)_keys,0,sizeof(_keys));
      std::memset((void*)_released_keys,0,sizeof(_released_keys));
      _is_keyESC = _is_keyF1 = _is_keyF2 = _is_keyF3 = _is_keyF4 = _is_keyF5 = _is_keyF6 = _is_keyF7 = _is_keyF8 = _is_keyF9 =
        _is_keyF10 = _is_keyF11 = _is_keyF12 = _is_keyPAUSE = _is_key1 = _is_key2 = _is_key3 = _is_key4 = _is_key5 = _is_key6 =
        _is_key7 = _is_key8 = _is_key9 = _is_key0 = _is_keyBACKSPACE = _is_keyINSERT = _is_keyHOME = _is_keyPAGEUP = _is_keyTAB =
        _is_keyQ = _is_keyW = _is_keyE = _is_keyR = _is_keyT = _is_keyY = _is_keyU = _is_keyI = _is_keyO = _is_keyP = _is_keyDELETE =
        _is_keyEND = _is_keyPAGEDOWN = _is_keyCAPSLOCK = _is_keyA = _is_keyS = _is_keyD = _is_keyF = _is_keyG = _is_keyH = _is_keyJ =
        _is_keyK = _is_keyL = _is_keyENTER = _is_keySHIFTLEFT = _is_keyZ = _is_keyX = _is_keyC = _is_keyV = _is_keyB = _is_keyN =
        _is_keyM = _is_keySHIFTRIGHT = _is_keyARROWUP = _is_keyCTRLLEFT = _is_keyAPPLEFT = _is_keyALT = _is_keySPACE = _is_keyALTGR = _is_keyAPPRIGHT =
        _is_keyMENU = _is_keyCTRLRIGHT = _is_keyARROWLEFT = _is_keyARROWDOWN = _is_keyARROWRIGHT = _is_keyPAD0 = _is_keyPAD1 = _is_keyPAD2 =
        _is_keyPAD3 = _is_keyPAD4 = _is_keyPAD5 = _is_keyPAD6 = _is_keyPAD7 = _is_keyPAD8 = _is_keyPAD9 = _is_keyPADADD = _is_keyPADSUB =
        _is_keyPADMUL = _is_keyPADDIV = false;
      _is_event = true;
      return *this;
    }

    CImgDisplay& set_key(const unsigned int keycode, const bool pressed=true) {
#define _cimg_set_key(k) if (keycode==cimg::key##k) _is_key##k = pressed;
      _cimg_set_key(ESC); _cimg_set_key(F1); _cimg_set_key(F2); _cimg_set_key(F3);
      _cimg_set_key(F4); _cimg_set_key(F5); _cimg_set_key(F6); _cimg_set_key(F7);
      _cimg_set_key(F8); _cimg_set_key(F9); _cimg_set_key(F10); _cimg_set_key(F11);
      _cimg_set_key(F12); _cimg_set_key(PAUSE); _cimg_set_key(1); _cimg_set_key(2);
      _cimg_set_key(3); _cimg_set_key(4); _cimg_set_key(5); _cimg_set_key(6);
      _cimg_set_key(7); _cimg_set_key(8); _cimg_set_key(9); _cimg_set_key(0);
      _cimg_set_key(BACKSPACE); _cimg_set_key(INSERT); _cimg_set_key(HOME);
      _cimg_set_key(PAGEUP); _cimg_set_key(TAB); _cimg_set_key(Q); _cimg_set_key(W);
      _cimg_set_key(E); _cimg_set_key(R); _cimg_set_key(T); _cimg_set_key(Y);
      _cimg_set_key(U); _cimg_set_key(I); _cimg_set_key(O); _cimg_set_key(P);
      _cimg_set_key(DELETE); _cimg_set_key(END); _cimg_set_key(PAGEDOWN);
      _cimg_set_key(CAPSLOCK); _cimg_set_key(A); _cimg_set_key(S); _cimg_set_key(D);
      _cimg_set_key(F); _cimg_set_key(G); _cimg_set_key(H); _cimg_set_key(J);
      _cimg_set_key(K); _cimg_set_key(L); _cimg_set_key(ENTER);
      _cimg_set_key(SHIFTLEFT); _cimg_set_key(Z); _cimg_set_key(X); _cimg_set_key(C);
      _cimg_set_key(V); _cimg_set_key(B); _cimg_set_key(N); _cimg_set_key(M);
      _cimg_set_key(SHIFTRIGHT); _cimg_set_key(ARROWUP); _cimg_set_key(CTRLLEFT);
      _cimg_set_key(APPLEFT); _cimg_set_key(ALT); _cimg_set_key(SPACE); _cimg_set_key(ALTGR);
      _cimg_set_key(APPRIGHT); _cimg_set_key(MENU); _cimg_set_key(CTRLRIGHT);
      _cimg_set_key(ARROWLEFT); _cimg_set_key(ARROWDOWN); _cimg_set_key(ARROWRIGHT);
      _cimg_set_key(PAD0); _cimg_set_key(PAD1); _cimg_set_key(PAD2);
      _cimg_set_key(PAD3); _cimg_set_key(PAD4); _cimg_set_key(PAD5);
      _cimg_set_key(PAD6); _cimg_set_key(PAD7); _cimg_set_key(PAD8);
      _cimg_set_key(PAD9); _cimg_set_key(PADADD); _cimg_set_key(PADSUB);
      _cimg_set_key(PADMUL); _cimg_set_key(PADDIV);
      if (pressed) {
        if (*_keys)
          std::memmove((void*)(_keys+1),(void*)_keys,sizeof(_keys) - sizeof(unsigned int));
        *_keys = keycode;
        if (*_released_keys) {
          std::memmove((void*)(_released_keys+1),(void*)_released_keys,sizeof(_released_keys) - sizeof(unsigned int));
          *_released_keys = 0;
        }
      } else {
        if (*_keys) {
          std::memmove((void*)(_keys+1),(void*)_keys,sizeof(_keys) - sizeof(unsigned int));
          *_keys = 0;
        }
        if (*_released_keys)
          std::memmove((void*)(_released_keys+1),(void*)_released_keys,sizeof(_released_keys) - sizeof(unsigned int));
        *_released_keys = keycode;
      }
      _is_event = keycode?true:false;
      return *this;
    }

    //! Flush all display events.
    CImgDisplay& flush() {
      set_key().set_button().set_wheel();
      _is_resized = _is_moved = _is_event = false;
      _fps_timer = _fps_frames = _timer = 0;
      _fps_fps = 0;
      return *this;
    }

    //! Synchronized waiting function. Same as cimg::wait().
    CImgDisplay& wait(const unsigned int milliseconds) {
      cimg::_sleep(milliseconds,_timer);
      return *this;
    }

    //! Wait for an event occuring on the current display.
    CImgDisplay& wait() {
      wait(*this);
      return *this;
    }

    //! Wait for any event occuring on the display \c disp1.
    static void wait(CImgDisplay& disp1) {
      disp1._is_event = 0;
      while (!disp1._is_closed && !disp1._is_event) wait_all();
    }

    //! Wait for any event occuring either on the display \c disp1 or \c disp2.
    static void wait(CImgDisplay& disp1, CImgDisplay& disp2) {
      disp1._is_event = disp2._is_event = 0;
      while ((!disp1._is_closed || !disp2._is_closed) &&
             !disp1._is_event && !disp2._is_event) wait_all();
    }

    //! Wait for any event occuring either on the display \c disp1, \c disp2 or \c disp3.
    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3) {
      disp1._is_event = disp2._is_event = disp3._is_event = 0;
      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed) &&
             !disp1._is_event && !disp2._is_event && !disp3._is_event) wait_all();
    }

    //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3 or \c disp4.
    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4) {
      disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = 0;
      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed) &&
             !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event) wait_all();
    }

    //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4 or \c disp5.
    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5) {
      disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = 0;
      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed) &&
             !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event) wait_all();
    }

    //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp6.
    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,
                     CImgDisplay& disp6) {
      disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =
        disp6._is_event = 0;
      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||
              !disp6._is_closed) &&
             !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&
             !disp6._is_event) wait_all();
    }

    //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp7.
    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,
                     CImgDisplay& disp6, CImgDisplay& disp7) {
      disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =
        disp6._is_event = disp7._is_event = 0;
      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||
              !disp6._is_closed || !disp7._is_closed) &&
             !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&
             !disp6._is_event && !disp7._is_event) wait_all();
    }

    //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp8.
    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,
                     CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8) {
      disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =
        disp6._is_event = disp7._is_event = disp8._is_event = 0;
      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||
              !disp6._is_closed || !disp7._is_closed || !disp8._is_closed) &&
             !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&
             !disp6._is_event && !disp7._is_event && !disp8._is_event) wait_all();
    }

    //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp9.
    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,
                     CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8, CImgDisplay& disp9) {
      disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =
        disp6._is_event = disp7._is_event = disp8._is_event = disp9._is_event = 0;
      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||
              !disp6._is_closed || !disp7._is_closed || !disp8._is_closed || !disp9._is_closed) &&
             !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&
             !disp6._is_event && !disp7._is_event && !disp8._is_event && !disp9._is_event) wait_all();
    }

    //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp10.
    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5,
                     CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8, CImgDisplay& disp9, CImgDisplay& disp10) {
      disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event =
        disp6._is_event = disp7._is_event = disp8._is_event = disp9._is_event = disp10._is_event = 0;
      while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed ||
              !disp6._is_closed || !disp7._is_closed || !disp8._is_closed || !disp9._is_closed || !disp10._is_closed) &&
             !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event &&
             !disp6._is_event && !disp7._is_event && !disp8._is_event && !disp9._is_event && !disp10._is_event) wait_all();
    }

#if cimg_display==0

    //! Wait for a window event in any CImg window.
    static void wait_all() {
      return _no_display_exception();
    }

#endif

    // X11-based implementation
    //--------------------------
#if cimg_display==1

    Atom _wm_window_atom, _wm_protocol_atom;
    Window _window, _background_window;
    Colormap _colormap;
    XImage *_image;
    void *_data;
#ifdef cimg_use_xshm
    XShmSegmentInfo *_shminfo;
#endif

    static int screen_width() {
      Display *const dpy = cimg::X11_attr().display;
      int res = 0;
      if (!dpy) {
        Display *const _dpy = XOpenDisplay(0);
        if (!_dpy)
          throw CImgDisplayException("CImgDisplay::screen_width() : Failed to open X11 display.");
        res = DisplayWidth(_dpy,DefaultScreen(_dpy));
        XCloseDisplay(_dpy);
      } else {
#ifdef cimg_use_xrandr
        if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution)
          res = cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].width;
        else res = DisplayWidth(dpy,DefaultScreen(dpy));
#else
        res = DisplayWidth(dpy,DefaultScreen(dpy));
#endif
      }
      return res;
    }

    static int screen_height() {
      Display *const dpy = cimg::X11_attr().display;
      int res = 0;
      if (!dpy) {
        Display *const _dpy = XOpenDisplay(0);
        if (!_dpy)
          throw CImgDisplayException("CImgDisplay::screen_height() : Failed to open X11 display.");
        res = DisplayHeight(_dpy,DefaultScreen(_dpy));
        XCloseDisplay(_dpy);
      } else {
#ifdef cimg_use_xrandr
        if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution)
          res = cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].height;
        else res = DisplayHeight(dpy,DefaultScreen(dpy));
#else
        res = DisplayHeight(dpy,DefaultScreen(dpy));
#endif
      }
      return res;
    }

    static void wait_all() {
      Display *const dpy = cimg::X11_attr().display;
      if (!dpy) return;
      XLockDisplay(dpy);
      bool flag = true;
      XEvent event;
      while (flag) {
        XNextEvent(dpy,&event);
        for (unsigned int i = 0; i<cimg::X11_attr().nb_wins; ++i)
          if (!cimg::X11_attr().wins[i]->_is_closed && event.xany.window==cimg::X11_attr().wins[i]->_window) {
            cimg::X11_attr().wins[i]->_handle_events(&event);
            if (cimg::X11_attr().wins[i]->_is_event) flag = false;
          }
      }
      XUnlockDisplay(dpy);
    }

    void _handle_events(const XEvent *const pevent) {
      Display *const dpy = cimg::X11_attr().display;
      XEvent event = *pevent;
      switch (event.type) {
      case ClientMessage : {
        if ((int)event.xclient.message_type==(int)_wm_protocol_atom &&
            (int)event.xclient.data.l[0]==(int)_wm_window_atom) {
          XUnmapWindow(cimg::X11_attr().display,_window);
          _is_closed = _is_event = true;
        }
      } break;
      case ConfigureNotify : {
        while (XCheckWindowEvent(dpy,_window,StructureNotifyMask,&event)) {}
        const unsigned int nw = event.xconfigure.width, nh = event.xconfigure.height;
        const int nx = event.xconfigure.x, ny = event.xconfigure.y;
        if (nw && nh && (nw!=_window_width || nh!=_window_height)) {
          _window_width = nw; _window_height = nh; _mouse_x = _mouse_y = -1;
          XResizeWindow(dpy,_window,_window_width,_window_height);
          _is_resized = _is_event = true;
        }
        if (nx!=_window_x || ny!=_window_y) { _window_x = nx; _window_y = ny; _is_moved = _is_event = true; }
      } break;
      case Expose : {
        while (XCheckWindowEvent(dpy,_window,ExposureMask,&event)) {}
        _paint(false);
        if (_is_fullscreen) {
          XWindowAttributes attr;
          XGetWindowAttributes(dpy,_window,&attr);
          while (attr.map_state!=IsViewable) XSync(dpy,False);
          XSetInputFocus(dpy,_window,RevertToParent,CurrentTime);
        }
      } break;
      case ButtonPress : {
        do {
          _mouse_x = event.xmotion.x; _mouse_y = event.xmotion.y;
          if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1;
          switch (event.xbutton.button) {
          case 1 : set_button(1); break;
          case 3 : set_button(2); break;
          case 2 : set_button(3); break;
          }
        } while (XCheckWindowEvent(dpy,_window,ButtonPressMask,&event));
      } break;
      case ButtonRelease : {
        do {
          _mouse_x = event.xmotion.x; _mouse_y = event.xmotion.y;
          if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1;
          switch (event.xbutton.button) {
          case 1 : set_button(1,false); break;
          case 3 : set_button(2,false); break;
          case 2 : set_button(3,false); break;
          case 4 : set_wheel(1); break;
          case 5 : set_wheel(-1); break;
          }
        } while (XCheckWindowEvent(dpy,_window,ButtonReleaseMask,&event));
      } break;
      case KeyPress : {
        char tmp = 0; KeySym ksym;
        XLookupString(&event.xkey,&tmp,1,&ksym,0);
        set_key((unsigned int)ksym,true);
      } break;
      case KeyRelease : {
        char tmp = 0; KeySym ksym;
        XLookupString(&event.xkey,&tmp,1,&ksym,0);
        set_key((unsigned int)ksym,false);
      } break;
      case EnterNotify: {
        while (XCheckWindowEvent(dpy,_window,EnterWindowMask,&event)) {}
        _mouse_x = event.xmotion.x;
        _mouse_y = event.xmotion.y;
        if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1;
      } break;
      case LeaveNotify : {
        while (XCheckWindowEvent(dpy,_window,LeaveWindowMask,&event)) {}
        _mouse_x = _mouse_y =-1; _is_event = true;
      } break;
      case MotionNotify : {
        while (XCheckWindowEvent(dpy,_window,PointerMotionMask,&event)) {}
        _mouse_x = event.xmotion.x;
        _mouse_y = event.xmotion.y;
        if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1;
        _is_event = true;
      } break;
      }
    }

    static void* _events_thread(void *) { // Only one thread to handle events for all opened display windows.
      Display *const dpy = cimg::X11_attr().display;
      XEvent event;
      pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
      for (;;) {
        XLockDisplay(dpy);
        bool event_flag = XCheckTypedEvent(dpy,ClientMessage,&event);
        if (!event_flag) event_flag = XCheckMaskEvent(dpy,
                                                      ExposureMask | StructureNotifyMask | ButtonPressMask|
                                                      KeyPressMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask|
                                                      ButtonReleaseMask | KeyReleaseMask,&event);
        if (event_flag)
          for (unsigned int i = 0; i<cimg::X11_attr().nb_wins; ++i)
            if (!cimg::X11_attr().wins[i]->_is_closed && event.xany.window==cimg::X11_attr().wins[i]->_window)
              cimg::X11_attr().wins[i]->_handle_events(&event);
        XUnlockDisplay(dpy);
        pthread_testcancel();
        cimg::sleep(8);
      }
      return 0;
    }

    void _set_colormap(Colormap& colormap, const unsigned int dim) {
      XColor palette[256];
      switch (dim) {
      case 1 : { // palette for greyscale images
        for (unsigned int index = 0; index<256; ++index) {
          palette[index].pixel = index;
          palette[index].red = palette[index].green = palette[index].blue = (unsigned short)(index<<8);
          palette[index].flags = DoRed | DoGreen | DoBlue;
        }
      } break;
      case 2 : { // palette for RG images
        for (unsigned int index = 0, r = 8; r<256; r+=16)
          for (unsigned int g = 8; g<256; g+=16) {
            palette[index].pixel = index;
            palette[index].red = palette[index].blue = (unsigned short)(r<<8);
            palette[index].green = (unsigned short)(g<<8);
            palette[index++].flags = DoRed | DoGreen | DoBlue;
          }
      } break;
      default : { // palette for RGB images
        for (unsigned int index = 0, r = 16; r<256; r+=32)
          for (unsigned int g = 16; g<256; g+=32)
            for (unsigned int b = 32; b<256; b+=64) {
              palette[index].pixel = index;
              palette[index].red = (unsigned short)(r<<8);
              palette[index].green = (unsigned short)(g<<8);
              palette[index].blue = (unsigned short)(b<<8);
              palette[index++].flags = DoRed | DoGreen | DoBlue;
            }
      }
      }
      XStoreColors(cimg::X11_attr().display,colormap,palette,256);
    }

    void _map_window() {
      Display *const dpy = cimg::X11_attr().display;
      bool is_exposed = false, is_mapped = false;
      XWindowAttributes attr;
      XEvent event;
      XMapRaised(dpy,_window);
      do { // Wait for the window to be mapped.
        XWindowEvent(dpy,_window,StructureNotifyMask | ExposureMask,&event);
        switch (event.type) {
        case MapNotify : is_mapped = true; break;
        case Expose : is_exposed = true; break;
        }
      } while (!is_exposed || !is_mapped);
      do { // Wait for the window to be visible.
        XGetWindowAttributes(dpy,_window,&attr);
        if (attr.map_state!=IsViewable) { XSync(dpy,False); cimg::sleep(10); }
      } while (attr.map_state!=IsViewable);
      _window_x = attr.x;
      _window_y = attr.y;
    }

    void _paint(const bool wait_expose=true) {
      if (_is_closed || !_image) return;
      Display *const dpy = cimg::X11_attr().display;
      if (wait_expose) { // Send an expose event sticked to display window to force repaint.
        static XEvent event;
        event.xexpose.type = Expose;
        event.xexpose.serial = 0;
        event.xexpose.send_event = True;
        event.xexpose.display = dpy;
        event.xexpose.window = _window;
        event.xexpose.x = 0;
        event.xexpose.y = 0;
        event.xexpose.width = width();
        event.xexpose.height = height();
        event.xexpose.count = 0;
        XSendEvent(dpy,_window,False,0,&event);
      } else { // Repaint directly (may be called from the expose event).
        GC gc = DefaultGC(dpy,DefaultScreen(dpy));
#ifdef cimg_use_xshm
        if (_shminfo) {
          const int completion_type = XShmGetEventBase(dpy) + ShmCompletion;
          XEvent event;
          XShmPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height,True);
          do { XNextEvent(dpy,&event); } while (event.type!=completion_type);  // Wait for the image drawing to be completed.
        } else XPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height);
#else
        XPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height);
#endif
      }
    }

    template<typename T>
    void _resize(T pixel_type, const unsigned int ndimx, const unsigned int ndimy, const bool force_redraw) {
      Display *const dpy = cimg::X11_attr().display;
      cimg::unused(pixel_type);

#ifdef cimg_use_xshm
      if (_shminfo) {
        XShmSegmentInfo *const nshminfo = new XShmSegmentInfo;
        XImage *const nimage = XShmCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),
                                               cimg::X11_attr().nb_bits,ZPixmap,0,nshminfo,ndimx,ndimy);
        if (!nimage) { delete nshminfo; return; }
        else {
          nshminfo->shmid = shmget(IPC_PRIVATE,ndimx*ndimy*sizeof(T),IPC_CREAT | 0777);
          if (nshminfo->shmid==-1) { XDestroyImage(nimage); delete nshminfo; return; }
          else {
            nshminfo->shmaddr = nimage->data = (char*)shmat(nshminfo->shmid,0,0);
            if (nshminfo->shmaddr==(char*)-1) { shmctl(nshminfo->shmid,IPC_RMID,0); XDestroyImage(nimage); delete nshminfo; return; }
            else {
              nshminfo->readOnly = False;
              cimg::X11_attr().is_shm_enabled = true;
              XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
              XShmAttach(dpy,nshminfo);
              XFlush(dpy);
              XSetErrorHandler(oldXErrorHandler);
              if (!cimg::X11_attr().is_shm_enabled) {
                shmdt(nshminfo->shmaddr);
                shmctl(nshminfo->shmid,IPC_RMID,0);
                XDestroyImage(nimage);
                delete nshminfo;
                return;
              } else {
                T *const ndata = (T*)nimage->data;
                if (force_redraw) _render_resize((T*)_data,_width,_height,ndata,ndimx,ndimy);
                else std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
                XShmDetach(dpy,_shminfo);
                XDestroyImage(_image);
                shmdt(_shminfo->shmaddr);
                shmctl(_shminfo->shmid,IPC_RMID,0);
                delete _shminfo;
                _shminfo = nshminfo;
                _image = nimage;
                _data = (void*)ndata;
              }
            }
          }
        }
      } else
#endif
        {
          T *ndata = (T*)std::malloc(ndimx*ndimy*sizeof(T));
          if (force_redraw) _render_resize((T*)_data,_width,_height,ndata,ndimx,ndimy);
          else std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
          _data = (void*)ndata;
          XDestroyImage(_image);
          _image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),
                                cimg::X11_attr().nb_bits,ZPixmap,0,(char*)_data,ndimx,ndimy,8,0);
        }
    }

    void _init_fullscreen() {
      if (!_is_fullscreen || _is_closed) return;
      Display *const dpy = cimg::X11_attr().display;
      _background_window = 0;

#ifdef cimg_use_xrandr
      int foo;
      if (XRRQueryExtension(dpy,&foo,&foo)) {
        XRRRotations(dpy,DefaultScreen(dpy),&cimg::X11_attr().curr_rotation);
        if (!cimg::X11_attr().resolutions) {
          cimg::X11_attr().resolutions = XRRSizes(dpy,DefaultScreen(dpy),&foo);
          cimg::X11_attr().nb_resolutions = (unsigned int)foo;
        }
        if (cimg::X11_attr().resolutions) {
          cimg::X11_attr().curr_resolution = 0;
          for (unsigned int i = 0; i<cimg::X11_attr().nb_resolutions; ++i) {
            const unsigned int
              nw = (unsigned int)(cimg::X11_attr().resolutions[i].width),
              nh = (unsigned int)(cimg::X11_attr().resolutions[i].height);
            if (nw>=_width && nh>=_height &&
                nw<=(unsigned int)(cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].width) &&
                nh<=(unsigned int)(cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].height))
              cimg::X11_attr().curr_resolution = i;
          }
          if (cimg::X11_attr().curr_resolution>0) {
            XRRScreenConfiguration *config = XRRGetScreenInfo(dpy,DefaultRootWindow(dpy));
            XRRSetScreenConfig(dpy,config,DefaultRootWindow(dpy),
                               cimg::X11_attr().curr_resolution,cimg::X11_attr().curr_rotation,CurrentTime);
            XRRFreeScreenConfigInfo(config);
            XSync(dpy,False);
          }
        }
      }
      if (!cimg::X11_attr().resolutions)
        cimg::warn(_cimgdisplay_instance
                   "init_fullscreen() : Xrandr extension not supported by the X server.",
                   cimgdisplay_instance);
#endif

      const unsigned int sx = screen_width(), sy = screen_height();
      if (sx==_width && sy==_height) return;
      XSetWindowAttributes winattr;
      winattr.override_redirect = True;
      _background_window = XCreateWindow(dpy,DefaultRootWindow(dpy),0,0,sx,sy,0,0,
                                         InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
      const unsigned int buf_size = sx*sy*(cimg::X11_attr().nb_bits==8?1:(cimg::X11_attr().nb_bits==16?2:4));
      void *background_data = std::malloc(buf_size);
      std::memset(background_data,0,buf_size);
      XImage *background_image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),cimg::X11_attr().nb_bits,
                                              ZPixmap,0,(char*)background_data,sx,sy,8,0);
      XEvent event;
      XSelectInput(dpy,_background_window,StructureNotifyMask);
      XMapRaised(dpy,_background_window);
      do XWindowEvent(dpy,_background_window,StructureNotifyMask,&event);
      while (event.type!=MapNotify);
      GC gc = DefaultGC(dpy,DefaultScreen(dpy));
#ifdef cimg_use_xshm
      if (_shminfo) XShmPutImage(dpy,_background_window,gc,background_image,0,0,0,0,sx,sy,False);
      else XPutImage(dpy,_background_window,gc,background_image,0,0,0,0,sx,sy);
#else
      XPutImage(dpy,_background_window,gc,background_image,0,0,0,0,sx,sy);
#endif
      XWindowAttributes attr;
      XGetWindowAttributes(dpy,_background_window,&attr);
      while (attr.map_state!=IsViewable) XSync(dpy,False);
      XDestroyImage(background_image);
    }

    void _desinit_fullscreen() {
      if (!_is_fullscreen) return;
      Display *const dpy = cimg::X11_attr().display;
      XUngrabKeyboard(dpy,CurrentTime);
#ifdef cimg_use_xrandr
      if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution) {
        XRRScreenConfiguration *config = XRRGetScreenInfo(dpy,DefaultRootWindow(dpy));
        XRRSetScreenConfig(dpy,config,DefaultRootWindow(dpy),0,cimg::X11_attr().curr_rotation,CurrentTime);
        XRRFreeScreenConfigInfo(config);
        XSync(dpy,False);
        cimg::X11_attr().curr_resolution = 0;
      }
#endif
      if (_background_window) XDestroyWindow(dpy,_background_window);
      _background_window = 0;
      _is_fullscreen = false;
    }

    static int _assign_xshm(Display *dpy, XErrorEvent *error) {
      cimg::unused(dpy,error);
      cimg::X11_attr().is_shm_enabled = false;
      return 0;
    }

    void _assign(const unsigned int dimw, const unsigned int dimh, const char *const ptitle=0,
                 const unsigned int normalization_type=3,
                 const bool fullscreen_flag=false, const bool closed_flag=false) {

      // Allocate space for window title
      const char *const nptitle = ptitle?ptitle:"";
      const unsigned int s = std::strlen(nptitle) + 1;
      char *const tmp_title = s?new char[s]:0;
      if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char));

      // Destroy previous display window if existing
      if (!is_empty()) assign();

      // Open X11 display and retrieve graphical properties.
      Display* &dpy = cimg::X11_attr().display;
      if (!dpy) {
        static const int xinit_status = XInitThreads();
        cimg::unused(xinit_status);
        dpy = XOpenDisplay(0);
        if (!dpy)
          throw CImgDisplayException(_cimgdisplay_instance
                                     "assign() : Failed to open X11 display.",
                                     cimgdisplay_instance);

        cimg::X11_attr().nb_bits = DefaultDepth(dpy,DefaultScreen(dpy));
        if (cimg::X11_attr().nb_bits!=8 && cimg::X11_attr().nb_bits!=16 && cimg::X11_attr().nb_bits!=24 && cimg::X11_attr().nb_bits!=32)
          throw CImgDisplayException(_cimgdisplay_instance
                                     "assign() : Invalid %u bits screen mode detected "
                                     "(only 8, 16, 24 and 32 bits modes are managed).",
                                     cimgdisplay_instance,
                                     cimg::X11_attr().nb_bits);
        XVisualInfo vtemplate;
        vtemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy,DefaultScreen(dpy)));
        int nb_visuals;
        XVisualInfo *vinfo = XGetVisualInfo(dpy,VisualIDMask,&vtemplate,&nb_visuals);
        if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11_attr().is_blue_first = true;
        cimg::X11_attr().byte_order = ImageByteOrder(dpy);
        XFree(vinfo);

        XLockDisplay(dpy);
        cimg::X11_attr().event_thread = new pthread_t;
        pthread_create(cimg::X11_attr().event_thread,0,_events_thread,0);
      } else XLockDisplay(dpy);

      // Set display variables.
      _width = cimg::min(dimw,(unsigned int)screen_width());
      _height = cimg::min(dimh,(unsigned int)screen_height());
      _normalization = normalization_type<4?normalization_type:3;
      _is_fullscreen = fullscreen_flag;
      _window_x = _window_y = 0;
      _is_closed = closed_flag;
      _title = tmp_title;
      flush();

      // Create X11 window (and LUT, if 8bits display)
      if (_is_fullscreen) {
        if (!_is_closed) _init_fullscreen();
        const unsigned int sx = screen_width(), sy = screen_height();
        XSetWindowAttributes winattr;
        winattr.override_redirect = True;
        _window = XCreateWindow(dpy,DefaultRootWindow(dpy),(sx-_width)/2,(sy-_height)/2,_width,_height,0,0,
                                InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
      } else
        _window = XCreateSimpleWindow(dpy,DefaultRootWindow(dpy),0,0,_width,_height,0,0L,0L);

      XSelectInput(dpy,_window,
                   ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask |
                   EnterWindowMask | LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask);

      XStoreName(dpy,_window,_title?_title:" ");
      if (cimg::X11_attr().nb_bits==8) {
        _colormap = XCreateColormap(dpy,_window,DefaultVisual(dpy,DefaultScreen(dpy)),AllocAll);
        _set_colormap(_colormap,3);
        XSetWindowColormap(dpy,_window,_colormap);
      }

      static const char *const _window_class = cimg_appname;
      XClassHint *const window_class = XAllocClassHint();
      window_class->res_name = (char*)_window_class;
      window_class->res_class = (char*)_window_class;
      XSetClassHint(dpy,_window,window_class);
      XFree(window_class);

      _window_width = _width;
      _window_height = _height;

      // Create XImage
#ifdef cimg_use_xshm
      _shminfo = 0;
      if (XShmQueryExtension(dpy)) {
        _shminfo = new XShmSegmentInfo;
        _image = XShmCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),cimg::X11_attr().nb_bits,ZPixmap,0,_shminfo,_width,_height);
        if (!_image) { delete _shminfo; _shminfo = 0; }
        else {
          _shminfo->shmid = shmget(IPC_PRIVATE,_image->bytes_per_line*_image->height,IPC_CREAT|0777);
          if (_shminfo->shmid==-1) { XDestroyImage(_image); delete _shminfo; _shminfo = 0; }
          else {
            _shminfo->shmaddr = _image->data = (char*)(_data = shmat(_shminfo->shmid,0,0));
            if (_shminfo->shmaddr==(char*)-1) { shmctl(_shminfo->shmid,IPC_RMID,0); XDestroyImage(_image); delete _shminfo; _shminfo = 0; }
            else {
              _shminfo->readOnly = False;
              cimg::X11_attr().is_shm_enabled = true;
              XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
              XShmAttach(dpy,_shminfo);
              XSync(dpy,False);
              XSetErrorHandler(oldXErrorHandler);
              if (!cimg::X11_attr().is_shm_enabled) {
                shmdt(_shminfo->shmaddr); shmctl(_shminfo->shmid,IPC_RMID,0); XDestroyImage(_image); delete _shminfo; _shminfo = 0;
              }
            }
          }
        }
      }
      if (!_shminfo)
#endif
        {
          const unsigned int buf_size = _width*_height*(cimg::X11_attr().nb_bits==8?1:(cimg::X11_attr().nb_bits==16?2:4));
          _data = std::malloc(buf_size);
          _image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),cimg::X11_attr().nb_bits,ZPixmap,0,(char*)_data,_width,_height,8,0);
        }

      _wm_window_atom = XInternAtom(dpy,"WM_DELETE_WINDOW",False);
      _wm_protocol_atom = XInternAtom(dpy,"WM_PROTOCOLS",False);
      XSetWMProtocols(dpy,_window,&_wm_window_atom,1);

      if (_is_fullscreen) XGrabKeyboard(dpy,_window,True,GrabModeAsync,GrabModeAsync,CurrentTime);
      cimg::X11_attr().wins[cimg::X11_attr().nb_wins++]=this;
      if (!_is_closed) _map_window(); else { _window_x = _window_y = cimg::type<int>::min(); }
      XUnlockDisplay(dpy);
    }

    CImgDisplay& assign() {
      if (is_empty()) return flush();
      Display *const dpy = cimg::X11_attr().display;
      XLockDisplay(dpy);

      // Remove display window from event thread list.
      unsigned int i;
      for (i = 0; i<cimg::X11_attr().nb_wins && cimg::X11_attr().wins[i]!=this; ++i) {}
      for (; i<cimg::X11_attr().nb_wins-1; ++i) cimg::X11_attr().wins[i] = cimg::X11_attr().wins[i+1];
      --cimg::X11_attr().nb_wins;

      // Destroy window, image, colormap and title.
      if (_is_fullscreen && !_is_closed) _desinit_fullscreen();
      XDestroyWindow(dpy,_window);
      _window = 0;
#ifdef cimg_use_xshm
      if (_shminfo) {
        XShmDetach(dpy,_shminfo);
        XDestroyImage(_image);
        shmdt(_shminfo->shmaddr);
        shmctl(_shminfo->shmid,IPC_RMID,0);
        delete _shminfo;
        _shminfo = 0;
      } else
#endif
        XDestroyImage(_image);
      _data = 0; _image = 0;
      if (cimg::X11_attr().nb_bits==8) XFreeColormap(dpy,_colormap);
      _colormap = 0;
      XSync(dpy,False);

      // Reset display variables
      delete[] _title;
      _width = _height = _normalization = _window_width = _window_height = 0;
      _window_x = _window_y = 0;
      _is_fullscreen = false;
      _is_closed = true;
      _min = _max = 0;
      _title = 0;
      flush();

      // End event thread and close display if necessary
      XUnlockDisplay(dpy);
      if (!cimg::X11_attr().nb_wins) {
        // Kill event thread
        //pthread_cancel(*cimg::X11_attr().event_thread);
        //XUnlockDisplay(cimg::X11_attr().display);
        //pthread_join(*cimg::X11_attr().event_thread,0);
        //delete cimg::X11_attr().event_thread;
        //cimg::X11_attr().event_thread = 0;
        // XUnlockDisplay(cimg::X11_attr().display); // <- This call make the library hang sometimes (fix required).
        // XCloseDisplay(cimg::X11_attr().display); // <- This call make the library hang sometimes (fix required).
        //cimg::X11_attr().display = 0;
      }
      return *this;
    }

    CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *const title=0,
                        const unsigned int normalization_type=3,
                        const bool fullscreen_flag=false, const bool closed_flag=false) {
      if (!dimw || !dimh) return assign();
      _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
      _min = _max = 0;
      std::memset(_data,0,(cimg::X11_attr().nb_bits==8?sizeof(unsigned char):
                          (cimg::X11_attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))*_width*_height);
      return paint();
    }

    template<typename T>
    CImgDisplay& assign(const CImg<T>& img, const char *const title=0,
                        const unsigned int normalization_type=3,
                        const bool fullscreen_flag=false, const bool closed_flag=false) {
      if (!img) return assign();
      CImg<T> tmp;
      const CImg<T>& nimg = (img._depth==1)?img:(tmp=img.get_projections2d(img._width/2,img._height/2,img._depth/2));
      _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag);
      if (_normalization==2) _min = (float)nimg.min_max(_max);
      return render(nimg).paint();
    }

    template<typename T>
    CImgDisplay& assign(const CImgList<T>& list, const char *const title=0,
                        const unsigned int normalization_type=3,
                        const bool fullscreen_flag=false, const bool closed_flag=false) {
      if (!list) return assign();
      CImg<T> tmp;
      const CImg<T> img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d(img._width/2,img._height/2,img._depth/2));
      _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag);
      if (_normalization==2) _min = (float)nimg.min_max(_max);
      return render(nimg).paint();
    }

    CImgDisplay& assign(const CImgDisplay& disp) {
      if (!disp) return assign();
      _assign(disp._width,disp._height,disp._title,disp._normalization,disp._is_fullscreen,disp._is_closed);
      std::memcpy(_data,disp._data,(cimg::X11_attr().nb_bits==8?sizeof(unsigned char):
                                    cimg::X11_attr().nb_bits==16?sizeof(unsigned short):
                                    sizeof(unsigned int))*_width*_height);
      return paint();
    }

    CImgDisplay& resize(const int nwidth, const int nheight, const bool force_redraw=true) {
      if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
      if (is_empty()) return assign(nwidth,nheight);
      Display *const dpy = cimg::X11_attr().display;
      const unsigned int
        tmpdimx = (nwidth>0)?nwidth:(-nwidth*_width/100),
        tmpdimy = (nheight>0)?nheight:(-nheight*_height/100),
        dimx = tmpdimx?tmpdimx:1,
        dimy = tmpdimy?tmpdimy:1;
      XLockDisplay(dpy);
      if (_window_width!=dimx || _window_height!=dimy) XResizeWindow(dpy,_window,dimx,dimy);
      if (_width!=dimx || _height!=dimy) switch (cimg::X11_attr().nb_bits) {
        case 8 :  { unsigned char pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break;
        case 16 : { unsigned short pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break;
        default : { unsigned int pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); }
        }
      _window_width = _width = dimx; _window_height = _height = dimy;
      _is_resized = false;
      XUnlockDisplay(dpy);
      if (_is_fullscreen) move((screen_width()-_width)/2,(screen_height()-_height)/2);
      if (force_redraw) return paint();
      return *this;
    }

    CImgDisplay& toggle_fullscreen(const bool force_redraw=true) {
      if (is_empty()) return *this;
      if (force_redraw) {
        const unsigned int buf_size = _width*_height*(cimg::X11_attr().nb_bits==8?1:(cimg::X11_attr().nb_bits==16?2:4));
        void *image_data = std::malloc(buf_size);
        std::memcpy(image_data,_data,buf_size);
        assign(_width,_height,_title,_normalization,!_is_fullscreen,false);
        std::memcpy(_data,image_data,buf_size);
        std::free(image_data);
        return paint();
      }
      return assign(_width,_height,_title,_normalization,!_is_fullscreen,false);
    }

    CImgDisplay& show() {
      if (is_empty() || !_is_closed) return *this;
      Display *const dpy = cimg::X11_attr().display;
      XLockDisplay(dpy);
      if (_is_fullscreen) _init_fullscreen();
      _map_window();
      _is_closed = false;
      XUnlockDisplay(dpy);
      return paint();
    }

    CImgDisplay& close() {
      if (is_empty() || _is_closed) return *this;
      Display *const dpy = cimg::X11_attr().display;
      XLockDisplay(dpy);
      if (_is_fullscreen) _desinit_fullscreen();
      XUnmapWindow(dpy,_window);
      _window_x = _window_y = -1;
      _is_closed = true;
      XUnlockDisplay(dpy);
      return *this;
    }

    CImgDisplay& move(const int posx, const int posy) {
      if (is_empty()) return *this;
      Display *const dpy = cimg::X11_attr().display;
      show();
      XLockDisplay(dpy);
      XMoveWindow(dpy,_window,posx,posy);
      _window_x = posx; _window_y = posy;
      _is_moved = false;
      XUnlockDisplay(dpy);
      return paint();
    }

    CImgDisplay& show_mouse() {
      if (is_empty()) return *this;
      Display *const dpy = cimg::X11_attr().display;
      XLockDisplay(dpy);
      XUndefineCursor(dpy,_window);
      XUnlockDisplay(dpy);
      return *this;
    }

    CImgDisplay& hide_mouse() {
      if (is_empty()) return *this;
      Display *const dpy = cimg::X11_attr().display;
      XLockDisplay(dpy);
      const char pix_data[8] = { 0 };
      XColor col;
      col.red = col.green = col.blue = 0;
      Pixmap pix = XCreateBitmapFromData(dpy,_window,pix_data,8,8);
      Cursor cur = XCreatePixmapCursor(dpy,pix,pix,&col,&col,0,0);
      XFreePixmap(dpy,pix);
      XDefineCursor(dpy,_window,cur);
      XUnlockDisplay(dpy);
      return *this;
    }

    CImgDisplay& set_mouse(const int posx, const int posy) {
      if (is_empty() || _is_closed) return *this;
      Display *const dpy = cimg::X11_attr().display;
      XLockDisplay(dpy);
      XWarpPointer(dpy,0L,_window,0,0,0,0,posx,posy);
      _mouse_x = posx; _mouse_y = posy;
      _is_moved = false;
      XSync(dpy,False);
      XUnlockDisplay(dpy);
      return *this;
    }

    CImgDisplay& set_title(const char *const format, ...) {
      if (is_empty()) return *this;
      char tmp[1024] = { 0 };
      va_list ap;
      va_start(ap, format);
      cimg_vsnprintf(tmp,sizeof(tmp),format,ap);
      va_end(ap);
      if (!std::strcmp(_title,tmp)) return *this;
      delete[] _title;
      const unsigned int s = std::strlen(tmp) + 1;
      _title = new char[s];
      std::memcpy(_title,tmp,s*sizeof(char));
      Display *const dpy = cimg::X11_attr().display;
      XLockDisplay(dpy);
      XStoreName(dpy,_window,tmp);
      XUnlockDisplay(dpy);
      return *this;
    }

    template<typename T>
    CImgDisplay& display(const CImg<T>& img) {
      if (!img)
        throw CImgArgumentException(_cimgdisplay_instance
                                    "display() : Empty specified image.",
                                    cimgdisplay_instance);
      if (is_empty()) return assign(img);
      return render(img).paint(false);
    }

    CImgDisplay& paint(const bool wait_expose=true) {
      if (is_empty()) return *this;
      Display *const dpy = cimg::X11_attr().display;
      XLockDisplay(dpy);
      _paint(wait_expose);
      XUnlockDisplay(dpy);
      return *this;
    }

    template<typename T>
    CImgDisplay& render(const CImg<T>& img, const bool flag8=false) {
      if (!img)
        throw CImgArgumentException(_cimgdisplay_instance
                                    "render() : Empty specified image.",
                                    cimgdisplay_instance);
      if (is_empty()) return *this;
      if (img._depth!=1) return render(img.get_projections2d(img._width/2,img._height/2,img._depth/2));
      if (cimg::X11_attr().nb_bits==8 && (img._width!=_width || img._height!=_height)) return render(img.get_resize(_width,_height,1,-100,1));
      if (cimg::X11_attr().nb_bits==8 && !flag8 && img._spectrum==3) {
        static const CImg<typename CImg<T>::ucharT> default_palette = CImg<typename CImg<T>::ucharT>::default_LUT256();
        return render(img.get_index(default_palette,true,false));
      }

      Display *const dpy = cimg::X11_attr().display;
      const T
        *data1 = img._data,
        *data2 = (img._spectrum>1)?img.data(0,0,0,1):data1,
        *data3 = (img._spectrum>2)?img.data(0,0,0,2):data1;

      if (cimg::X11_attr().is_blue_first) cimg::swap(data1,data3);
      XLockDisplay(dpy);

      if (!_normalization || (_normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
        _min = _max = 0;
        switch (cimg::X11_attr().nb_bits) {
        case 8 : { // 256 color palette, no normalization
          _set_colormap(_colormap,img._spectrum);
          unsigned char *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data:new unsigned char[img._width*img._height];
          unsigned char *ptrd = (unsigned char*)ndata;
          switch (img._spectrum) {
          case 1 : for (unsigned int xy = img._width*img._height; xy>0; --xy) (*ptrd++) = (unsigned char)*(data1++);
            break;
          case 2 : for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++);
              (*ptrd++) = (R&0xf0) | (G>>4);
            } break;
          default : for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
              (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
            }
          }
          if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height); delete[] ndata; }
        } break;
        case 16 : { // 16 bits colors, no normalization
          unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data:new unsigned short[img._width*img._height];
          unsigned char *ptrd = (unsigned char*)ndata;
          const unsigned int M = 248;
          switch (img._spectrum) {
          case 1 :
            if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char val = (unsigned char)*(data1++), G = val>>2;
              *(ptrd++) = (val&M) | (G>>3);
              *(ptrd++) = (G<<5) | (G>>1);
            } else for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char val = (unsigned char)*(data1++), G = val>>2;
              *(ptrd++) = (G<<5) | (G>>1);
              *(ptrd++) = (val&M) | (G>>3);
            }
            break;
          case 2 :
            if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char G = (unsigned char)*(data2++)>>2;
              *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
              *(ptrd++) = (G<<5);
            } else for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char G = (unsigned char)*(data2++)>>2;
              *(ptrd++) = (G<<5);
              *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
            }
            break;
          default :
            if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char G = (unsigned char)*(data2++)>>2;
              *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
              *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
            } else for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char G = (unsigned char)*(data2++)>>2;
              *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
              *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
            }
          }
          if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height); delete[] ndata; }
        } break;
        default : { // 24 bits colors, no normalization
          unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data:new unsigned int[img._width*img._height];
          if (sizeof(int)==4) { // 32 bits int uses optimized version
            unsigned int *ptrd = ndata;
            switch (img._spectrum) {
            case 1 :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (unsigned int xy = img._width*img._height; xy>0; --xy) {
                  const unsigned char val = (unsigned char)*(data1++);
                  *(ptrd++) = (val<<16) | (val<<8) | val;
                }
              else
               for (unsigned int xy = img._width*img._height; xy>0; --xy) {
                 const unsigned char val = (unsigned char)*(data1++);
                  *(ptrd++) = (val<<16) | (val<<8) | val;
                }
              break;
            case 2 :
              if (cimg::X11_attr().byte_order==cimg::endianness())
               for (unsigned int xy = img._width*img._height; xy>0; --xy)
                  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
              else
               for (unsigned int xy = img._width*img._height; xy>0; --xy)
                  *(ptrd++) = ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
              break;
            default :
              if (cimg::X11_attr().byte_order==cimg::endianness())
               for (unsigned int xy = img._width*img._height; xy>0; --xy)
                  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
              else
               for (unsigned int xy = img._width*img._height; xy>0; --xy)
                  *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
            }
          } else {
            unsigned char *ptrd = (unsigned char*)ndata;
            switch (img._spectrum) {
            case 1 :
              if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) {
                *(ptrd++) = 0;
                *(ptrd++) = (unsigned char)*(data1++);
                *(ptrd++) = 0;
                *(ptrd++) = 0;
              } else for (unsigned int xy = img._width*img._height; xy>0; --xy) {
                *(ptrd++) = 0;
                *(ptrd++) = 0;
                *(ptrd++) = (unsigned char)*(data1++);
                *(ptrd++) = 0;
              }
              break;
            case 2 :
              if (cimg::X11_attr().byte_order) cimg::swap(data1,data2);
              for (unsigned int xy = img._width*img._height; xy>0; --xy) {
                *(ptrd++) = 0;
                *(ptrd++) = (unsigned char)*(data2++);
                *(ptrd++) = (unsigned char)*(data1++);
                *(ptrd++) = 0;
              }
              break;
            default :
              if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) {
                *(ptrd++) = 0;
                *(ptrd++) = (unsigned char)*(data1++);
                *(ptrd++) = (unsigned char)*(data2++);
                *(ptrd++) = (unsigned char)*(data3++);
              } else for (unsigned int xy = img._width*img._height; xy>0; --xy) {
                *(ptrd++) = (unsigned char)*(data3++);
                *(ptrd++) = (unsigned char)*(data2++);
                *(ptrd++) = (unsigned char)*(data1++);
                *(ptrd++) = 0;
              }
            }
          }
          if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height); delete[] ndata; }
        }
        }
      } else {
        if (_normalization==3) {
          if (cimg::type<T>::is_float()) _min = (float)img.min_max(_max);
          else { _min = (float)cimg::type<T>::min(); _max = (float)cimg::type<T>::max(); }
        } else if ((_min>_max) || _normalization==1) _min = (float)img.min_max(_max);
        const float delta = _max - _min, mm = 255/(delta?delta:1.0f);
        switch (cimg::X11_attr().nb_bits) {
        case 8 : { // 256 color palette, with normalization
          _set_colormap(_colormap,img._spectrum);
          unsigned char *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data:new unsigned char[img._width*img._height];
          unsigned char *ptrd = (unsigned char*)ndata;
          switch (img._spectrum) {
          case 1 : for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char R = (unsigned char)((*(data1++)-_min)*mm);
              *(ptrd++) = R;
            } break;
          case 2 : for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char
                R = (unsigned char)((*(data1++)-_min)*mm),
                G = (unsigned char)((*(data2++)-_min)*mm);
            (*ptrd++) = (R&0xf0) | (G>>4);
          } break;
          default :
            for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char
                R = (unsigned char)((*(data1++)-_min)*mm),
                G = (unsigned char)((*(data2++)-_min)*mm),
                B = (unsigned char)((*(data3++)-_min)*mm);
              *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
            }
          }
          if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height); delete[] ndata; }
        } break;
        case 16 : { // 16 bits colors, with normalization
          unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data:new unsigned short[img._width*img._height];
          unsigned char *ptrd = (unsigned char*)ndata;
          const unsigned int M = 248;
          switch (img._spectrum) {
          case 1 :
            if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char val = (unsigned char)((*(data1++)-_min)*mm), G = val>>2;
              *(ptrd++) = (val&M) | (G>>3);
              *(ptrd++) = (G<<5) | (val>>3);
            } else for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char val = (unsigned char)((*(data1++)-_min)*mm), G = val>>2;
              *(ptrd++) = (G<<5) | (val>>3);
              *(ptrd++) = (val&M) | (G>>3);
            }
            break;
          case 2 :
            if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char G = (unsigned char)((*(data2++)-_min)*mm)>>2;
              *(ptrd++) = ((unsigned char)((*(data1++)-_min)*mm)&M) | (G>>3);
              *(ptrd++) = (G<<5);
            } else for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char G = (unsigned char)((*(data2++)-_min)*mm)>>2;
              *(ptrd++) = (G<<5);
              *(ptrd++) = ((unsigned char)((*(data1++)-_min)*mm)&M) | (G>>3);
            }
            break;
          default :
            if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char G = (unsigned char)((*(data2++)-_min)*mm)>>2;
              *(ptrd++) = ((unsigned char)((*(data1++)-_min)*mm)&M) | (G>>3);
              *(ptrd++) = (G<<5) | ((unsigned char)((*(data3++)-_min)*mm)>>3);
            } else for (unsigned int xy = img._width*img._height; xy>0; --xy) {
              const unsigned char G = (unsigned char)((*(data2++)-_min)*mm)>>2;
              *(ptrd++) = (G<<5) | ((unsigned char)((*(data3++)-_min)*mm)>>3);
              *(ptrd++) = ((unsigned char)((*(data1++)-_min)*mm)&M) | (G>>3);
            }
          }
          if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height); delete[] ndata; }
        } break;
        default : { // 24 bits colors, with normalization
          unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data:new unsigned int[img._width*img._height];
          if (sizeof(int)==4) { // 32 bits int uses optimized version
            unsigned int *ptrd = ndata;
            switch (img._spectrum) {
            case 1 :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (unsigned int xy = img._width*img._height; xy>0; --xy) {
                  const unsigned char val = (unsigned char)((*(data1++)-_min)*mm);
                  *(ptrd++) = (val<<16) | (val<<8) | val;
                }
              else
                for (unsigned int xy = img._width*img._height; xy>0; --xy) {
                  const unsigned char val = (unsigned char)((*(data1++)-_min)*mm);
                  *(ptrd++) = (val<<24) | (val<<16) | (val<<8);
                }
              break;
            case 2 :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (unsigned int xy = img._width*img._height; xy>0; --xy)
                  *(ptrd++) =
                    ((unsigned char)((*(data1++)-_min)*mm)<<16) |
                    ((unsigned char)((*(data2++)-_min)*mm)<<8);
              else
                for (unsigned int xy = img._width*img._height; xy>0; --xy)
                  *(ptrd++) =
                    ((unsigned char)((*(data2++)-_min)*mm)<<16) |
                    ((unsigned char)((*(data1++)-_min)*mm)<<8);
              break;
            default :
              if (cimg::X11_attr().byte_order==cimg::endianness())
                for (unsigned int xy = img._width*img._height; xy>0; --xy)
                  *(ptrd++) =
                    ((unsigned char)((*(data1++)-_min)*mm)<<16) |
                    ((unsigned char)((*(data2++)-_min)*mm)<<8) |
                    (unsigned char)((*(data3++)-_min)*mm);
              else
                for (unsigned int xy = img._width*img._height; xy>0; --xy)
                  *(ptrd++) =
                    ((unsigned char)((*(data3++)-_min)*mm)<<24) |
                    ((unsigned char)((*(data2++)-_min)*mm)<<16) |
                    ((unsigned char)((*(data1++)-_min)*mm)<<8);
            }
          } else {
            unsigned char *ptrd = (unsigned char*)ndata;
            switch (img._spectrum) {
            case 1 :
              if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) {
                const unsigned char val = (unsigned char)((*(data1++)-_min)*mm);
                (*ptrd++) = 0;
                (*ptrd++) = val;
                (*ptrd++) = val;
                (*ptrd++) = val;
              } else for (unsigned int xy = img._width*img._height; xy>0; --xy) {
                const unsigned char val = (unsigned char)((*(data1++)-_min)*mm);
                (*ptrd++) = val;
                (*ptrd++) = val;
                (*ptrd++) = val;
                (*ptrd++) = 0;
              }
              break;
            case 2 :
              if (cimg::X11_attr().byte_order) cimg::swap(data1,data2);
              for (unsigned int xy = img._width*img._height; xy>0; --xy) {
                (*ptrd++) = 0;
                (*ptrd++) = (unsigned char)((*(data2++)-_min)*mm);
                (*ptrd++) = (unsigned char)((*(data1++)-_min)*mm);
                (*ptrd++) = 0;
              }
              break;
            default :
              if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) {
                (*ptrd++) = 0;
                (*ptrd++) = (unsigned char)((*(data1++)-_min)*mm);
                (*ptrd++) = (unsigned char)((*(data2++)-_min)*mm);
                (*ptrd++) = (unsigned char)((*(data3++)-_min)*mm);
              } else for (unsigned int xy = img._width*img._height; xy>0; --xy) {
                (*ptrd++) = (unsigned char)((*(data3++)-_min)*mm);
                (*ptrd++) = (unsigned char)((*(data2++)-_min)*mm);
                (*ptrd++) = (unsigned char)((*(data1++)-_min)*mm);
                (*ptrd++) = 0;
              }
            }
          }
          if (ndata!=_data) { _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height); delete[] ndata; }
        }
        }
      }
      XUnlockDisplay(dpy);
      return *this;
    }

    template<typename T>
    const CImgDisplay& snapshot(CImg<T>& img) const {
      if (is_empty()) { img.assign(); return *this; }
      const unsigned char *ptrs = (unsigned char*)_data;
      img.assign(_width,_height,1,3);
      T
        *data1 = img.data(0,0,0,0),
        *data2 = img.data(0,0,0,1),
        *data3 = img.data(0,0,0,2);
      if (cimg::X11_attr().is_blue_first) cimg::swap(data1,data3);
      switch (cimg::X11_attr().nb_bits) {
      case 8 : {
        for (unsigned int xy = img._width*img._height; xy>0; --xy) {
          const unsigned char val = *(ptrs++);
          *(data1++) = val&0xe0;
          *(data2++) = (val&0x1c)<<3;
          *(data3++) = val<<6;
        }
      } break;
      case 16 : {
        if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) {
          const unsigned char val0 = *(ptrs++), val1 = *(ptrs++);
          *(data1++) = val0&0xf8;
          *(data2++) = (val0<<5) | ((val1&0xe0)>>5);
          *(data3++) = val1<<3;
        } else for (unsigned int xy = img._width*img._height; xy>0; --xy) {
          const unsigned short val0 = *(ptrs++), val1 = *(ptrs++);
          *(data1++) = val1&0xf8;
          *(data2++) = (val1<<5) | ((val0&0xe0)>>5);
          *(data3++) = val0<<3;
        }
      } break;
      default : {
        if (cimg::X11_attr().byte_order) for (unsigned int xy = img._width*img._height; xy>0; --xy) {
          ++ptrs;
          *(data1++) = *(ptrs++);
          *(data2++) = *(ptrs++);
          *(data3++) = *(ptrs++);
        } else for (unsigned int xy = img._width*img._height; xy>0; --xy) {
          *(data3++) = *(ptrs++);
          *(data2++) = *(ptrs++);
          *(data1++) = *(ptrs++);
          ++ptrs;
        }
      }
      }
      return *this;
    }

    // Windows-based implementation.
    //-------------------------------
#elif cimg_display==2

    CLIENTCREATESTRUCT _ccs;
    BITMAPINFO _bmi;
    unsigned int *_data;
    DEVMODE _curr_mode;
    HWND _window;
    HWND _background_window;
    HDC _hdc;
    HANDLE _thread;
    HANDLE _is_created;
    HANDLE _mutex;
    bool _is_mouse_tracked;
    bool _is_cursor_visible;

    static int screen_width() {
      DEVMODE mode;
      mode.dmSize = sizeof(DEVMODE);
      mode.dmDriverExtra = 0;
      EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
      return mode.dmPelsWidth;
    }

    static int screen_height() {
      DEVMODE mode;
      mode.dmSize = sizeof(DEVMODE);
      mode.dmDriverExtra = 0;
      EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
      return mode.dmPelsHeight;
    }

    static void wait_all() {
      WaitForSingleObject(cimg::Win32_attr().wait_event,INFINITE);
    }

    static LRESULT APIENTRY _handle_events(HWND window,UINT msg,WPARAM wParam,LPARAM lParam) {
#ifdef _WIN64
      CImgDisplay *const disp = (CImgDisplay*)GetWindowLongPtr(window,GWLP_USERDATA);
#else
      CImgDisplay *const disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA);
#endif
      MSG st_msg;
      switch (msg) {
      case WM_CLOSE :
        disp->_mouse_x = disp->_mouse_y = -1;
        disp->_window_x = disp->_window_y = 0;
        disp->set_button().set_key(0).set_key(0,false)._is_closed = true;
        ReleaseMutex(disp->_mutex);
        ShowWindow(disp->_window,SW_HIDE);
        disp->_is_event = true;
        SetEvent(cimg::Win32_attr().wait_event);
        return 0;
      case WM_SIZE : {
        while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
        WaitForSingleObject(disp->_mutex,INFINITE);
        const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam);
        if (nw && nh && (nw!=disp->_width || nh!=disp->_height)) {
          disp->_window_width = nw;
          disp->_window_height = nh;
          disp->_mouse_x = disp->_mouse_y = -1;
          disp->_is_resized = disp->_is_event = true;
          SetEvent(cimg::Win32_attr().wait_event);
        }
        ReleaseMutex(disp->_mutex);
      } break;
      case WM_MOVE : {
        while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
        WaitForSingleObject(disp->_mutex,INFINITE);
        const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam));
        if (nx!=disp->_window_x || ny!=disp->_window_y) {
          disp->_window_x = nx;
          disp->_window_y = ny;
          disp->_is_moved = disp->_is_event = true;
          SetEvent(cimg::Win32_attr().wait_event);
        }
        ReleaseMutex(disp->_mutex);
      } break;
      case WM_PAINT :
        disp->paint();
        break;
      case WM_KEYDOWN :
        disp->set_key((unsigned int)wParam);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case WM_KEYUP :
        disp->set_key((unsigned int)wParam,false);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case WM_MOUSEMOVE : {
        while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE)) {}
        disp->_mouse_x = LOWORD(lParam);
        disp->_mouse_y = HIWORD(lParam);
#if (_WIN32_WINNT>=0x0400) && !defined(NOTRACKMOUSEEVENT)
        if (!disp->_is_mouse_tracked) {
          TRACKMOUSEEVENT tme;
          tme.cbSize = sizeof(TRACKMOUSEEVENT);
          tme.dwFlags = TME_LEAVE;
          tme.hwndTrack = disp->_window;
          if (TrackMouseEvent(&tme)) disp->_is_mouse_tracked = true;
        }
#endif
        if (disp->_mouse_x<0 || disp->_mouse_y<0 || disp->_mouse_x>=disp->width() || disp->_mouse_y>=disp->height())
          disp->_mouse_x = disp->_mouse_y = -1;
        disp->_is_event = true;
        SetEvent(cimg::Win32_attr().wait_event);
      } break;
      case WM_MOUSELEAVE : {
        disp->_mouse_x = disp->_mouse_y = -1;
        disp->_is_mouse_tracked = false;
      } break;
      case WM_LBUTTONDOWN :
        disp->set_button(1);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case WM_RBUTTONDOWN :
        disp->set_button(2);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case WM_MBUTTONDOWN :
        disp->set_button(3);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case WM_LBUTTONUP :
        disp->set_button(1,false);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case WM_RBUTTONUP :
        disp->set_button(2,false);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case WM_MBUTTONUP :
        disp->set_button(3,false);
        SetEvent(cimg::Win32_attr().wait_event);
        break;
      case 0x020A : // WM_MOUSEWHEEL:
        disp->set_wheel((int)((short)HIWORD(wParam))/120);
        SetEvent(cimg::Win32_attr().wait_event);
      case WM_SETCURSOR :
        if (disp->_is_cursor_visible) ShowCursor(TRUE);
        else ShowCursor(FALSE);
        break;
      }
      return DefWindowProc(window,msg,wParam,lParam);
    }

    static DWORD WINAPI _events_thread(void* arg) {
      CImgDisplay *const disp = (CImgDisplay*)(((void**)arg)[0]);
      const char *const title = (const char*)(((void**)arg)[1]);
      MSG msg;
      delete[] (void**)arg;
      disp->_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
      disp->_bmi.bmiHeader.biWidth = disp->width();
      disp->_bmi.bmiHeader.biHeight = -disp->height();
      disp->_bmi.bmiHeader.biPlanes = 1;
      disp->_bmi.bmiHeader.biBitCount = 32;
      disp->_bmi.bmiHeader.biCompression = BI_RGB;
      disp->_bmi.bmiHeader.biSizeImage = 0;
      disp->_bmi.bmiHeader.biXPelsPerMeter = 1;
      disp->_bmi.bmiHeader.biYPelsPerMeter = 1;
      disp->_bmi.bmiHeader.biClrUsed = 0;
      disp->_bmi.bmiHeader.biClrImportant = 0;
      disp->_data = new unsigned int[disp->_width*disp->_height];
      if (!disp->_is_fullscreen) { // Normal window
        RECT rect;
        rect.left = rect.top = 0; rect.right = disp->_width-1; rect.bottom = disp->_height-1;
        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
        const int
          border1 = (rect.right - rect.left + 1 - disp->_width)/2,
          border2 = rect.bottom - rect.top + 1 - disp->_height - border1;
        disp->_window = CreateWindowA("MDICLIENT",title?title:" ",
                                     WS_OVERLAPPEDWINDOW | (disp->_is_closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,
                                     disp->_width + 2*border1, disp->_height + border1 + border2,
                                     0,0,0,&(disp->_ccs));
        if (!disp->_is_closed) {
          GetWindowRect(disp->_window,&rect);
          disp->_window_x = rect.left + border1;
          disp->_window_y = rect.top + border2;
        } else disp->_window_x = disp->_window_y = 0;
      } else { // Fullscreen window
        const unsigned int sx = screen_width(), sy = screen_height();
        disp->_window = CreateWindowA("MDICLIENT",title?title:" ",
                                     WS_POPUP | (disp->_is_closed?0:WS_VISIBLE), (sx-disp->_width)/2, (sy-disp->_height)/2,
                                     disp->_width,disp->_height,0,0,0,&(disp->_ccs));
        disp->_window_x = disp->_window_y = 0;
      }
      SetForegroundWindow(disp->_window);
      disp->_hdc = GetDC(disp->_window);
      disp->_window_width = disp->_width;
      disp->_window_height = disp->_height;
      disp->flush();
#ifdef _WIN64
      SetWindowLongPtr(disp->_window,GWLP_USERDATA,(LONG_PTR)disp);
      SetWindowLongPtr(disp->_window,GWLP_WNDPROC,(LONG_PTR)_handle_events);
#else
      SetWindowLong(disp->_window,GWL_USERDATA,(LONG)disp);
      SetWindowLong(disp->_window,GWL_WNDPROC,(LONG)_handle_events);
#endif
      SetEvent(disp->_is_created);
      while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg);
      return 0;
    }

    CImgDisplay& _update_window_pos() {
      if (_is_closed) _window_x = _window_y = -1;
      else {
        RECT rect;
        rect.left = rect.top = 0; rect.right = _width-1; rect.bottom = _height-1;
        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
        const int
          border1 = (rect.right - rect.left + 1 - _width)/2,
          border2 = rect.bottom - rect.top + 1 - _height - border1;
        GetWindowRect(_window,&rect);
        _window_x = rect.left + border1;
        _window_y = rect.top + border2;
      }
      return *this;
    }

    void _init_fullscreen() {
      _background_window = 0;
      if (!_is_fullscreen || _is_closed) _curr_mode.dmSize = 0;
      else {
        DEVMODE mode;
        unsigned int imode = 0, ibest = 0, bestbpp = 0, bw = ~0U, bh = ~0U;
        for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(0,imode,&mode); ++imode) {
          const unsigned int nw = mode.dmPelsWidth, nh = mode.dmPelsHeight;
          if (nw>=_width && nh>=_height && mode.dmBitsPerPel>=bestbpp && nw<=bw && nh<=bh) {
            bestbpp = mode.dmBitsPerPel;
            ibest = imode;
            bw = nw; bh = nh;
          }
        }
        if (bestbpp) {
          _curr_mode.dmSize = sizeof(DEVMODE); _curr_mode.dmDriverExtra = 0;
          EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&_curr_mode);
          EnumDisplaySettings(0,ibest,&mode);
          ChangeDisplaySettings(&mode,0);
        } else _curr_mode.dmSize = 0;

        const unsigned int sx = screen_width(), sy = screen_height();
        if (sx!=_width || sy!=_height) {
          CLIENTCREATESTRUCT background_ccs;
          _background_window = CreateWindowA("MDICLIENT","",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs);
          SetForegroundWindow(_background_window);
        }
      }
    }

    void _desinit_fullscreen() {
      if (!_is_fullscreen) return;
      if (_background_window) DestroyWindow(_background_window);
      _background_window = 0;
      if (_curr_mode.dmSize) ChangeDisplaySettings(&_curr_mode,0);
      _is_fullscreen = false;
    }

    CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *const ptitle=0,
                         const unsigned int normalization_type=3,
                         const bool fullscreen_flag=false, const bool closed_flag=false) {

      // Allocate space for window title
      const char *const nptitle = ptitle?ptitle:"";
      const unsigned int s = std::strlen(nptitle) + 1;
      char *const tmp_title = s?new char[s]:0;
      if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char));

      // Destroy previous window if existing
      if (!is_empty()) assign();

      // Set display variables
      _width = cimg::min(dimw,(unsigned int)screen_width());
      _height = cimg::min(dimh,(unsigned int)screen_height());
      _normalization = normalization_type<4?normalization_type:3;
      _is_fullscreen = fullscreen_flag;
      _window_x = _window_y = 0;
      _is_closed = closed_flag;
      _is_cursor_visible = true;
      _is_mouse_tracked = false;
      _title = tmp_title;
      flush();
      if (_is_fullscreen) _init_fullscreen();

      // Create event thread
      void *const arg = (void*)(new void*[2]);
      ((void**)arg)[0] = (void*)this;
      ((void**)arg)[1] = (void*)_title;
      unsigned long ThreadID = 0;
      _mutex = CreateMutex(0,FALSE,0);
      _is_created = CreateEvent(0,FALSE,FALSE,0);
      _thread = CreateThread(0,0,_events_thread,arg,0,&ThreadID);
      WaitForSingleObject(_is_created,INFINITE);
      return *this;
    }

    CImgDisplay& assign() {
      if (is_empty()) return flush();
      DestroyWindow(_window);
      TerminateThread(_thread,0);
      delete[] _data;
      delete[] _title;
      _data = 0;
      _title = 0;
      if (_is_fullscreen) _desinit_fullscreen();
      _width = _height = _normalization = _window_width = _window_height = 0;
      _window_x = _window_y = 0;
      _is_fullscreen = false;
      _is_closed = true;
      _min = _max = 0;
      _title = 0;
      flush();
      return *this;
    }

    CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *const title=0,
                        const unsigned int normalization_type=3,
                        const bool fullscreen_flag=false, const bool closed_flag=false) {
      if (!dimw || !dimh) return assign();
      _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
      _min = _max = 0;
      std::memset(_data,0,sizeof(unsigned int)*_width*_height);
      return paint();
    }

    template<typename T>
    CImgDisplay& assign(const CImg<T>& img, const char *const title=0,
                        const unsigned int normalization_type=3,
                        const bool fullscreen_flag=false, const bool closed_flag=false) {
      if (!img) return assign();
      CImg<T> tmp;
      const CImg<T>& nimg = (img._depth==1)?img:(tmp=img.get_projections2d(img._width/2,img._height/2,img._depth/2));
      _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag);
      if (_normalization==2) _min = (float)nimg.min_max(_max);
      return display(nimg);
    }

    template<typename T>
    CImgDisplay& assign(const CImgList<T>& list, const char *const title=0,
                        const unsigned int normalization_type=3,
                        const bool fullscreen_flag=false, const bool closed_flag=false) {
      if (!list) return assign();
      CImg<T> tmp;
      const CImg<T> img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d(img._width/2,img._height/2,img._depth/2));
      _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag);
      if (_normalization==2) _min = (float)nimg.min_max(_max);
      return display(nimg);
    }

    CImgDisplay& assign(const CImgDisplay& disp) {
      if (!disp) return assign();
      _assign(disp._width,disp._height,disp._title,disp._normalization,disp._is_fullscreen,disp._is_closed);
      std::memcpy(_data,disp._data,sizeof(unsigned int)*_width*_height);
      return paint();
    }

    CImgDisplay& resize(const int nwidth, const int nheight, const bool force_redraw=true) {
      if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
      if (is_empty()) return assign(nwidth,nheight);
      const unsigned int
        tmpdimx = (nwidth>0)?nwidth:(-nwidth*_width/100),
        tmpdimy = (nheight>0)?nheight:(-nheight*_height/100),
        dimx = tmpdimx?tmpdimx:1,
        dimy = tmpdimy?tmpdimy:1;
      if (_window_width!=dimx || _window_height!=dimy) {
        RECT rect; rect.left = rect.top = 0; rect.right = dimx - 1; rect.bottom = dimy - 1;
        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
        const int cwidth = rect.right - rect.left + 1, cheight = rect.bottom - rect.top + 1;
        SetWindowPos(_window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
      }
      if (_width!=dimx || _height!=dimy) {
        unsigned int *const ndata = new unsigned int[dimx*dimy];
        if (force_redraw) _render_resize(_data,_width,_height,ndata,dimx,dimy);
        else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
        delete[] _data;
        _data = ndata;
        _bmi.bmiHeader.biWidth = dimx;
        _bmi.bmiHeader.biHeight = -(int)dimy;
        _width = dimx;
        _height = dimy;
      }
      _window_width = dimx; _window_height = dimy;
      _is_resized = false;
      if (_is_fullscreen) move((screen_width()-_width)/2,(screen_height()-_height)/2);
      if (force_redraw) return paint();
      return *this;
    }

    CImgDisplay& toggle_fullscreen(const bool force_redraw=true) {
      if (is_empty()) return *this;
      if (force_redraw) {
        const unsigned int buf_size = _width*_height*4;
        void *odata = std::malloc(buf_size);
        std::memcpy(odata,_data,buf_size);
        assign(_width,_height,_title,_normalization,!_is_fullscreen,false);
        std::memcpy(_data,odata,buf_size);
        std::free(odata);
        return paint();
      }
      return assign(_width,_height,_title,_normalization,!_is_fullscreen,false);
    }

    CImgDisplay& show() {
      if (is_empty() || !_is_closed) return *this;
      _is_closed = false;
      if (_is_fullscreen) _init_fullscreen();
      ShowWindow(_window,SW_SHOW);
      _update_window_pos();
      return paint();
    }

    CImgDisplay& close() {
      if (is_empty() || _is_closed) return *this;
      _is_closed = true;
      if (_is_fullscreen) _desinit_fullscreen();
      ShowWindow(_window,SW_HIDE);
      _window_x = _window_y = 0;
      return *this;
    }

    CImgDisplay& move(const int posx, const int posy) {
      if (is_empty()) return *this;
      if (!_is_fullscreen) {
        RECT rect; rect.left = rect.top = 0; rect.right = _window_width-1; rect.bottom = _window_height-1;
        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
        const int border1 = (rect.right-rect.left+1-_width)/2, border2 = rect.bottom-rect.top+1-_height-border1;
        SetWindowPos(_window,0,posx-border1,posy-border2,0,0,SWP_NOSIZE | SWP_NOZORDER);
      } else SetWindowPos(_window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER);
      _window_x = posx;
      _window_y = posy;
      _is_moved = false;
      return show();
    }

    CImgDisplay& show_mouse() {
      if (is_empty()) return *this;
      _is_cursor_visible = true;
      ShowCursor(TRUE);
      SendMessage(_window,WM_SETCURSOR,0,0);
      return *this;
    }

    CImgDisplay& hide_mouse() {
      if (is_empty()) return *this;
      _is_cursor_visible = false;
      ShowCursor(FALSE);
      SendMessage(_window,WM_SETCURSOR,0,0);
      return *this;
    }

    CImgDisplay& set_mouse(const int posx, const int posy) {
      if (_is_closed || posx<0 || posy<0) return *this;
      _update_window_pos();
      const int res = (int)SetCursorPos(_window_x + posx,_window_y + posy);
      if (res) { _mouse_x = posx; _mouse_y = posy; }
      return *this;
    }

    CImgDisplay& set_title(const char *const format, ...) {
      if (is_empty()) return *this;
      char tmp[1024] = { 0 };
      va_list ap;
      va_start(ap, format);
      cimg_vsnprintf(tmp,sizeof(tmp),format,ap);
      va_end(ap);
      if (!std::strcmp(_title,tmp)) return *this;
      delete[] _title;
      const unsigned int s = std::strlen(tmp) + 1;
      _title = new char[s];
      std::memcpy(_title,tmp,s*sizeof(char));
      SetWindowTextA(_window, tmp);
      return *this;
    }

    template<typename T>
    CImgDisplay& display(const CImg<T>& img) {
      if (!img)
        throw CImgArgumentException(_cimgdisplay_instance
                                    "display() : Empty specified image.",
                                    cimgdisplay_instance);
      if (is_empty()) return assign(img);
      return render(img).paint();
    }

    CImgDisplay& paint() {
      if (_is_closed) return *this;
      WaitForSingleObject(_mutex,INFINITE);
      SetDIBitsToDevice(_hdc,0,0,_width,_height,0,0,0,_height,_data,&_bmi,DIB_RGB_COLORS);
      ReleaseMutex(_mutex);
      return *this;
    }

    template<typename T>
    CImgDisplay& render(const CImg<T>& img) {
      if (!img)
        throw CImgArgumentException(_cimgdisplay_instance
                                    "render() : Empty specified image.",
                                    cimgdisplay_instance);

      if (is_empty()) return *this;
      if (img._depth!=1) return render(img.get_projections2d(img._width/2,img._height/2,img._depth/2));

      const T
        *data1 = img._data,
        *data2 = (img._spectrum>=2)?img.data(0,0,0,1):data1,
        *data3 = (img._spectrum>=3)?img.data(0,0,0,2):data1;

      WaitForSingleObject(_mutex,INFINITE);
      unsigned int
        *const ndata = (img._width==_width && img._height==_height)?_data:new unsigned int[img._width*img._height],
        *ptrd = ndata;

      if (!_normalization || (_normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
        _min = _max = 0;
        switch (img._spectrum) {
        case 1 : {
          for (unsigned int xy = img._width*img._height; xy>0; --xy) {
            const unsigned char val = (unsigned char)*(data1++);
            *(ptrd++) = (val<<16) | (val<<8) | val;
          }
        } break;
        case 2 : {
          for (unsigned int xy = img._width*img._height; xy>0; --xy)
            *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
        } break;
        default : {
          for (unsigned int xy = img._width*img._height; xy>0; --xy)
            *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
        }
        }
      } else {
        if (_normalization==3) {
          if (cimg::type<T>::is_float()) _min = (float)img.min_max(_max);
          else { _min = (float)cimg::type<T>::min(); _max = (float)cimg::type<T>::max(); }
        } else if ((_min>_max) || _normalization==1) _min = (float)img.min_max(_max);
        const float delta = _max - _min, mm = 255/(delta?delta:1.0f);
        switch (img._spectrum) {
        case 1 : {
          for (unsigned int xy = img._width*img._height; xy>0; --xy) {
            const unsigned char val = (unsigned char)((*(data1++)-_min)*mm);
            *(ptrd++) = (val<<16) | (val<<8) | val;
          }
        } break;
        case 2 : {
          for (unsigned int xy = img._width*img._height; xy>0; --xy) {
            const unsigned char
              R = (unsigned char)((*(data1++)-_min)*mm),
              G = (unsigned char)((*(data2++)-_min)*mm);
            *(ptrd++) = (R<<16) | (G<<8);
          }
        } break;
        default : {
          for (unsigned int xy = img._width*img._height; xy>0; --xy) {
            const unsigned char
              R = (unsigned char)((*(data1++)-_min)*mm),
              G = (unsigned char)((*(data2++)-_min)*mm),
              B = (unsigned char)((*(data3++)-_min)*mm);
            *(ptrd++) = (R<<16) | (G<<8) | B;
          }
        }
        }
      }
      if (ndata!=_data) { _render_resize(ndata,img._width,img._height,_data,_width,_height); delete[] ndata; }
      ReleaseMutex(_mutex);
      return *this;
    }

    template<typename T>
    const CImgDisplay& snapshot(CImg<T>& img) const {
      if (is_empty()) { img.assign(); return *this; }
      const unsigned int *ptrs = _data;
      img.assign(_width,_height,1,3);
      T
        *data1 = img.data(0,0,0,0),
        *data2 = img.data(0,0,0,1),
        *data3 = img.data(0,0,0,2);
      for (unsigned int xy = img._width*img._height; xy>0; --xy) {
        const unsigned int val = *(ptrs++);
        *(data1++) = (unsigned char)(val>>16);
        *(data2++) = (unsigned char)((val>>8)&0xFF);
        *(data3++) = (unsigned char)(val&0xFF);
      }
      return *this;
    }
#endif

    //@}
  };

  /*
   #--------------------------------------
   #
   #
   #
   # Definition of the CImg<T> structure
   #
   #
   #
   #--------------------------------------
   */

  //! Class representing an image (up to 4 dimensions wide), each pixel being of type \c T.
  /**
     This is the main class of the %CImg Library. It declares and constructs
     an image, allows access to its pixel values, and is able to perform various image operations.

     \par Image representation

     A %CImg image is defined as an instance of the container \c CImg<T>, which contains a regular grid of pixels,
     each pixel value being of type \c T. The image grid can have up to 4 dimensions : width, height, depth
     and number of channels.
     Usually, the three first dimensions are used to describe spatial coordinates <tt>(x,y,z)</tt>, while the number of channels
     is rather used as a vector-valued dimension (it may describe the R,G,B color channels for instance).
     If you need a fifth dimension, you can use image lists \c CImgList<T> rather than simple images \c CImg<T>.

     Thus, the \c CImg<T> class is able to represent volumetric images of vector-valued pixels,
     as well as images with less dimensions (1d scalar signal, 2d color images, ...).
     Most member functions of the class CImg<\c T> are designed to handle this maximum case of (3+1) dimensions.

     Concerning the pixel value type \c T :
     fully supported template types are the basic C++ types : <tt>unsigned char, char, short, unsigned int, int,
     unsigned long, long, float, double, ... </tt>.
     Typically, fast image display can be done using <tt>CImg<unsigned char></tt> images,
     while complex image processing algorithms may be rather coded using <tt>CImg<float></tt> or <tt>CImg<double></tt>
     images that have floating-point pixel values. The default value for the template T is \c float.
     Using your own template types may be possible. However, you will certainly have to define the complete set
     of arithmetic and logical operators for your class.

     \par Image structure

     The \c CImg<T> structure contains \e six fields :
     - \c _width defines the number of \a columns of the image (size along the X-axis).
     - \c _height defines the number of \a rows of the image (size along the Y-axis).
     - \c _depth defines the number of \a slices of the image (size along the Z-axis).
     - \c _spectrum defines the number of \a channels of the image (size along the C-axis).
     - \c _data defines a \a pointer to the \a pixel \a data (of type \c T).
     - \c _is_shared is a boolean that tells if the memory buffer \c data is shared with
       another image.

     You can access these fields publicly although it is recommended to use the dedicated functions
     width(), height(), depth(), spectrum() and ptr() to do so.
     Image dimensions are not limited to a specific range (as long as you got enough available memory).
     A value of \e 1 usually means that the corresponding dimension is \a flat.
     If one of the dimensions is \e 0, or if the data pointer is null, the image is considered as \e empty.
     Empty images should not contain any pixel data and thus, will not be processed by CImg member functions
     (a CImgInstanceException will be thrown instead).
     Pixel data are stored in memory, in a non interlaced mode (See \ref cimg_storage).

     \par Image declaration and construction

     Declaring an image can be done by using one of the several available constructors.
     Here is a list of the most used :

     - Construct images from arbitrary dimensions :
         - <tt>CImg<char> img;</tt> declares an empty image.
         - <tt>CImg<unsigned char> img(128,128);</tt> declares a 128x128 greyscale image with
         \c unsigned \c char pixel values.
         - <tt>CImg<double> img(3,3);</tt> declares a 3x3 matrix with \c double coefficients.
         - <tt>CImg<unsigned char> img(256,256,1,3);</tt> declares a 256x256x1x3 (color) image
         (colors are stored as an image with three channels).
         - <tt>CImg<double> img(128,128,128);</tt> declares a 128x128x128 volumetric and greyscale image
         (with \c double pixel values).
         - <tt>CImg<> img(128,128,128,3);</tt> declares a 128x128x128 volumetric color image
         (with \c float pixels, which is the default value of the template parameter \c T).
         - \b Note : images pixels are <b>not automatically initialized to 0</b>. You may use the function \c fill() to
         do it, or use the specific constructor taking 5 parameters like this :
         <tt>CImg<> img(128,128,128,3,0);</tt> declares a 128x128x128 volumetric color image with all pixel values to 0.

     - Construct images from filenames :
         - <tt>CImg<unsigned char> img("image.jpg");</tt> reads a JPEG color image from the file "image.jpg".
         - <tt>CImg<float> img("analyze.hdr");</tt> reads a volumetric image (ANALYZE7.5 format) from the file "analyze.hdr".
         - \b Note : You need to install <a href="http://www.imagemagick.org">ImageMagick</a>
         to be able to read common compressed image formats (JPG,PNG, ...) (See \ref cimg_files_io).

     - Construct images from C-style arrays :
         - <tt>CImg<int> img(data_buffer,256,256);</tt> constructs a 256x256 greyscale image from a \c int* buffer
         \c data_buffer (of size 256x256=65536).
         - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,false);</tt> constructs a 256x256 color image
         from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels follow each others).
         - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,true);</tt> constructs a 256x256 color image
         from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels are multiplexed).

         The complete list of constructors can be found <a href="#constructors">here</a>.

     \par Most useful functions

     The \c CImg<T> class contains a lot of functions that operates on images.
     Some of the most useful are :

     - operator()() : allows to access or write pixel values.
     - display() : displays the image in a new window.
  **/
  template<typename T>
  struct CImg {

    unsigned int _width, _height, _depth, _spectrum;
    bool _is_shared;
    T *_data;

    //! Simple iterator type, to loop through each pixel value of an image instance.
    /**
       \note
       - The \c CImg<T>::iterator type is defined to be a <tt>T*</tt>.
       - You will seldom have to use iterators in %CImg, most classical operations
         being achieved (often in a faster way) using methods of \c CImg<T>.
       \par Sample code :
       \code
       CImg<float> img("reference.jpg");                                         // Load image from file.
       for (CImg<float>::iterator it = img.begin(), it<img.end(); ++it) *it = 0; // Set all pixels to '0', through a CImg iterator.
       img.fill(0);                                                              // Do the same with a built-in method.
       \endcode
       \sa const_iterator.
   **/
    typedef T* iterator;

    //! Simple const iterator type, to loop through each pixel value of a \c const image instance.
    /**
       \note
       - The \c CImg<T>::const_iterator type is defined to be a \c const \c T*.
       - You will seldom have to use iterators in %CImg, most classical operations
         being achieved (often in a faster way) using methods of \c CImg<T>.
       \par Sample code :
       \code
       const CImg<float> img("reference.jpg");                                    // Load image from file.
       float sum = 0;
       for (CImg<float>::iterator it = img.begin(), it<img.end(); ++it) sum+=*it; // Compute sum of all pixel values, through a CImg iterator.
       const float sum2 = img.sum();                                              // Do the same with a built-in method.
       \endcode
       \sa iterator.
    **/
    typedef const T* const_iterator;

    //! Pixel value type.
    /**
       Refer to the type of the pixel values of an image instance.
       \note
       - The \c CImg<T>::value_type type of a \c CImg<T> is defined to be a \c T.
       - \c CImg<T>::value_type is actually not used in %CImg methods. It has been mainly defined for
         compatibility with STL naming conventions.
    **/
    typedef T value_type;

    // Define common types related to template type T.
    typedef typename cimg::superset<T,bool>::type Tbool;
    typedef typename cimg::superset<T,unsigned char>::type Tuchar;
    typedef typename cimg::superset<T,char>::type Tchar;
    typedef typename cimg::superset<T,unsigned short>::type Tushort;
    typedef typename cimg::superset<T,short>::type Tshort;
    typedef typename cimg::superset<T,unsigned int>::type Tuint;
    typedef typename cimg::superset<T,int>::type Tint;
    typedef typename cimg::superset<T,unsigned long>::type Tulong;
    typedef typename cimg::superset<T,long>::type Tlong;
    typedef typename cimg::superset<T,float>::type Tfloat;
    typedef typename cimg::superset<T,double>::type Tdouble;
    typedef typename cimg::last<T,bool>::type boolT;
    typedef typename cimg::last<T,unsigned char>::type ucharT;
    typedef typename cimg::last<T,char>::type charT;
    typedef typename cimg::last<T,unsigned short>::type ushortT;
    typedef typename cimg::last<T,short>::type shortT;
    typedef typename cimg::last<T,unsigned int>::type uintT;
    typedef typename cimg::last<T,int>::type intT;
    typedef typename cimg::last<T,unsigned long>::type ulongT;
    typedef typename cimg::last<T,long>::type longT;
    typedef typename cimg::last<T,float>::type floatT;
    typedef typename cimg::last<T,double>::type doubleT;

    //@}
    //---------------------------
    //
    //! \name Plugins
    //@{
    //---------------------------
#ifdef cimg_plugin
#include cimg_plugin
#endif
#ifdef cimg_plugin1
#include cimg_plugin1
#endif
#ifdef cimg_plugin2
#include cimg_plugin2
#endif
#ifdef cimg_plugin3
#include cimg_plugin3
#endif
#ifdef cimg_plugin4
#include cimg_plugin4
#endif
#ifdef cimg_plugin5
#include cimg_plugin5
#endif
#ifdef cimg_plugin6
#include cimg_plugin6
#endif
#ifdef cimg_plugin7
#include cimg_plugin7
#endif
#ifdef cimg_plugin8
#include cimg_plugin8
#endif

    //@}
    //---------------------------------------------------------
    //
    //! \name Constructors / Destructor / Instance Management
    //@{
    //---------------------------------------------------------

    //! Destructor.
    /**
       Destroy current image instance.
       \note
       - The pixel buffer data() is deallocated if necessary, e.g. for non-empty and non-shared image instances.
       - Destroying an empty or shared image does nothing actually.
       \warning
       - When destroying a non-shared image, make sure that you will \e not operate on a remaining shared image
         that shares its buffer with the destroyed instance, in order to avoid further invalid memory access (to a deallocated buffer).
       \sa CImg(),
           assign().
    **/
    ~CImg() {
      if (!_is_shared) delete[] _data;
    }

    //! Default constructor.
    /**
       Construct a new empty image instance.
       \note
       - An empty image has no pixel data and all of its dimensions width(), height(), depth(), spectrum()
         are set to \c 0, as well as its pixel buffer pointer data().
       - An empty image may be re-assigned afterwards, e.g. with the family of assign(unsigned int,unsigned int,unsigned int,unsigned int) methods,
         or by operator=(const CImg<t>&). In all cases, the type of pixels stays \c T.
       - An empty image is never shared.
       \par Sample code :
       \code
       CImg<float> img1, img2;      // Construct two empty images.
       img1.assign(256,256,1,3);    // Re-assign 'img1' to be a 256x256x1x3 (color) image.
       img2 = img1.get_rand(0,255); // Re-assign 'img2' to be a random-valued version of 'img1'.
       img2.assign();               // Re-assign 'img2' to be an empty image again.
       \endcode
       \sa ~CImg(),
           assign(),
           is_empty().
    **/
    CImg():_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {}

    //! Construct image with specified size.
    /**
       Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, with pixels of type \c T.
       \param size_x : Desired image width().
       \param size_y : Desired image height().
       \param size_z : Desired image depth().
       \param size_c : Desired image spectrum().
       \note
       - It is able to create only \e non-shared images, and allocates thus a pixel buffer data() for each constructed image instance.
       - Setting one dimension \c size_x,\c size_y,\c size_z or \c size_c to \c 0 leads to the construction of an \e empty image.
       - A \c CImgInstanceException is thrown when the pixel buffer cannot be allocated (e.g. when requested size is too big for available memory).
       \warning
       - The allocated pixel buffer is \e not filled with a default value, and is likely to contain garbage values.
         In order to initialize pixel values during construction (e.g. with \c 0), use constructor
         CImg(unsigned int,unsigned int,unsigned int,unsigned int,T) instead.
       \par Sample code :
       \code
       CImg<float> img1(256,256,1,3);   // Construct a 256x256x1x3 (color) image, filled with garbage values.
       CImg<float> img2(256,256,1,3,0); // Construct a 256x256x1x3 (color) image, filled with value '0'.
       \endcode
       \sa CImg(unsigned int,unsigned int,unsigned int,unsigned int,T),
           assign(unsigned int,unsigned int,unsigned int,unsigned int).
    **/
    explicit CImg(const unsigned int size_x, const unsigned int size_y=1, const unsigned int size_z=1, const unsigned int size_c=1):
      _is_shared(false) {
      const unsigned int siz = size_x*size_y*size_z*size_c;
      if (siz) {
        _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
        try { _data = new T[siz]; } catch (...) {
          _width = _height = _depth = _spectrum = 0; _data = 0;
          throw CImgInstanceException(_cimg_instance
                                      "CImg() : Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                      cimg_instance,
                                      cimg::strbuffersize(size_x*size_y*size_z*size_c*sizeof(T)),size_x,size_y,size_z,size_c);
        }
      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }
    }

    //! Construct image with specified size and initialize pixel values.
    /**
       Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, with pixels of type \c T, and set all pixel
       values to specified \c value.
       \param size_x : Desired image width().
       \param size_y : Desired image height().
       \param size_z : Desired image depth().
       \param size_c : Desired image spectrum().
       \param value : Value used for initialization.
       \note
       - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int),
         but it also fills the pixel buffer with the specified \c value.
       \warning
       - It cannot be used to construct a vector-valued image and initialize it with \e vector-valued pixels (e.g. RGB vector, for color images).
         For this task, you may use fillC() after construction.
       \sa CImg(unsigned int,unsigned int,unsigned int,unsigned int),
           assign(unsigned int,unsigned int,unsigned int,unsigned int,T).
    **/
    CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const T value):
      _is_shared(false) {
      const unsigned int siz = size_x*size_y*size_z*size_c;
      if (siz) {
        _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
        try { _data = new T[siz]; } catch (...) {
          _width = _height = _depth = _spectrum = 0; _data = 0;
          throw CImgInstanceException(_cimg_instance
                                      "CImg() : Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                      cimg_instance,
                                      cimg::strbuffersize(size_x*size_y*size_z*size_c*sizeof(T)),size_x,size_y,size_z,size_c);
        }
        fill(value);
      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }
    }

    //! Construct image with specified size and initialize pixel values from a sequence of integers.
    /**
       Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, with pixels of type \c T, and initialize pixel
       values from the specified sequence of integers \c value0,\c value1,\c ...
       \param size_x : Desired image width().
       \param size_y : Desired image height().
       \param size_z : Desired image depth().
       \param size_c : Desired image spectrum().
       \param value0 : First value of the initialization sequence (must be an \e integer).
       \param value1 : Second value of the initialization sequence (must be an \e integer).
       \param ...
       \note
       - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it also fills
         the pixel buffer with a sequence of specified integer values.
       \warning
       - You must specify \e exactly \c size_x*\c size_y*\c size_z*\c size_c integers in the initialization sequence.
         Otherwise, the constructor may crash or fill your image pixels with garbage.
       \par Sample code :
       \code
       const CImg<float> img(2,2,1,3,      // Construct a 2x2 color (RGB) image.
                             0,255,0,255,  // Set the 4 values for the red component.
                             0,0,255,255,  // Set the 4 values for the green component.
                             64,64,64,64); // Set the 4 values for the blue component.
       img.resize(150,150).display();
       \endcode
       \image html ref_constructor1.jpg
       \sa CImg(unsigned int,unsigned int,unsigned int,unsigned int),
           CImg(unsigned int,unsigned int,unsigned int,unsigned int,double,double,...),
           assign(unsigned int,unsigned int,unsigned int,unsigned int,int,int,...).
     **/
    CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,
         const int value0, const int value1, ...):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
#define _CImg_stdarg(img,a0,a1,N,t) { \
        unsigned int _siz = (unsigned int)N; \
        if (_siz--) { \
          va_list ap; \
          va_start(ap,a1); \
          T *ptrd = (img)._data; \
          *(ptrd++) = (T)a0; \
          if (_siz--) { \
            *(ptrd++) = (T)a1; \
            for (; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \
          } \
          va_end(ap); \
        } \
      }
      assign(size_x,size_y,size_z,size_c);
      _CImg_stdarg(*this,value0,value1,size_x*size_y*size_z*size_c,int);
    }

    //! Construct image with specified size and initialize pixel values from a sequence of doubles.
    /**
       Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, with pixels of type \c T, and initialize pixel
       values from the specified sequence of doubles \c value0,\c value1,\c ...
       \param size_x : Desired image width().
       \param size_y : Desired image height().
       \param size_z : Desired image depth().
       \param size_c : Desired image spectrum().
       \param value0 : First value of the initialization sequence (must be a \e double).
       \param value1 : Second value of the initialization sequence (must be a \e double).
       \param ...
       \note
       - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int,int,int,...), but
         takes a sequence of double values instead of integers.
       \warning
       - You must specify \e exactly \c dx*\c dy*\c dz*\c dc doubles in the initialization sequence.
         Otherwise, the constructor may crash or fill your image with garbage.
         For instance, the code below will probably crash on most platforms :
         \code
         const CImg<float> img(2,2,1,1, 0.5,0.5,255,255); // FAIL : The two last arguments are 'int', not 'double' !
         \endcode
       \sa CImg(unsigned int,unsigned int,unsigned int,unsigned int),
           CImg(unsigned int,unsigned int,unsigned int,unsigned int,int,int,...),
           assign(unsigned int,unsigned int,unsigned int,unsigned int,double,double,...).
     **/
    CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,
         const double value0, const double value1, ...):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
      assign(size_x,size_y,size_z,size_c);
      _CImg_stdarg(*this,value0,value1,size_x*size_y*size_z*size_c,double);
    }

    //! Construct image with specified size and initialize pixel values from a value string.
    /**
       Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, with pixels of type \c T, and initializes pixel
       values from the specified string \c values.
       \param size_x : Desired image width().
       \param size_y : Desired image height().
       \param size_z : Desired image depth().
       \param size_c : Desired image spectrum().
       \param values : Value string describing the way pixel values are set.
       \param repeat_values : Flag telling if the value filling process is periodic.
       \note
       - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it also fills
         the pixel buffer with values described in the value string \c values.
       - Value string \c values may describe two different filling processes :
         - Either \c values is a sequences of values assigned to the image pixels, as in <tt>"1,2,3,7,8,2"</tt>.
           In this case, set \c repeat_values to \c true to periodically fill the image with the value sequence.
         - Either, \c values is a formula, as in <tt>"cos(x/10)*sin(y/20)"</tt>. In this case, parameter \c repeat_values is pointless.
       - For both cases, specifying \c repeat_values is mandatory. It disambiguates the possible overloading of constructor
         CImg(unsigned int,unsigned int,unsigned int,unsigned int,T) with \c T being a <tt>const char*</tt>.
       - A \c CImgArgumentException is thrown when an invalid value string \c values is specified.
       \par Sample code :
       \code
       const CImg<float> img1(129,129,1,3,"0,64,128,192,255",true),                   // Construct image filled from a value sequence.
                         img2(129,129,1,3,"if(c==0,255*abs(cos(x/10)),1.8*y)",false); // Construct image filled from a formula.
       (img1,img2).display();
       \endcode
       \image html ref_constructor2.jpg
       \sa CImg(unsigned int,unsigned int,unsigned int,unsigned int),
           assign(unsigned int,unsigned int,unsigned int,unsigned int,const char*,bool).
     **/
    CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,
         const char *const values, const bool repeat_values):_is_shared(false) {
      const unsigned int siz = size_x*size_y*size_z*size_c;
      if (siz) {
        _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
        try { _data = new T[siz]; } catch (...) {
          _width = _height = _depth = _spectrum = 0; _data = 0;
          throw CImgInstanceException(_cimg_instance
                                      "CImg() : Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                      cimg_instance,
                                      cimg::strbuffersize(size_x*size_y*size_z*size_c*sizeof(T)),size_x,size_y,size_z,size_c);
        }
        fill(values,repeat_values);
      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }
    }

    //! Construct image with specified size and initialize pixel values from a memory buffer.
    /**
       Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, with pixels of type \c T, and initializes pixel
       values from the specified \c t* memory buffer.
       \param values : Pointer to the input memory buffer.
       \param size_x : Desired image width().
       \param size_y : Desired image height().
       \param size_z : Desired image depth().
       \param size_c : Desired image spectrum().
       \param is_shared : Flag telling if input memory buffer must be shared by the current instance.
       \note
       - If \c is_shared is \c false, the image instance allocates its own pixel buffer, and values from the specified input buffer
         are copied to the instance buffer. If buffer types \c T and \c t are different, a regular static cast is performed during buffer copy.
       - Otherwise, the image instance does \e not allocate a new buffer, and uses the input memory buffer as its own pixel buffer. This case
         requires that types \c T and \c t are the same. Later, destroying such a shared image will not deallocate the pixel buffer,
         this task being obviously charged to the initial buffer allocator.
       - A \c CImgInstanceException is thrown when the pixel buffer cannot be allocated (e.g. when requested size is too big for available memory).
       \warning
       - You must take care when operating on a shared image, since it may have an invalid pixel buffer pointer data() (e.g. already deallocated).
       \par Sample code :
       \code
       unsigned char tab[256*256] = { 0 };
       CImg<unsigned char> img1(tab,256,256,1,1,false), // Construct new non-shared image from buffer 'tab'.
                           img2(tab,256,256,1,1,true);  // Construct new shared-image from buffer 'tab'.
       tab[1024] = 255;                                 // Here, 'img2' is indirectly modified, but not 'img1'.
       \endcode
       \sa CImg(unsigned int,unsigned int,unsigned int,unsigned int),
           assign(const t*,unsigned int,unsigned int,unsigned int,unsigned int,bool),
           is_shared().
    **/
    template<typename t>
    CImg(const t *const values, const unsigned int size_x, const unsigned int size_y=1,
         const unsigned int size_z=1, const unsigned int size_c=1, const bool is_shared=false):_is_shared(false) {
      if (is_shared) {
        _width = _height = _depth = _spectrum = 0; _data = 0;
        throw CImgArgumentException(_cimg_instance
                                    "CImg() : Invalid construction request of a (%u,%u,%u,%u) shared instance from a (%s*) buffer "
                                    "(pixel types are different).",
                                    cimg_instance,
                                    size_x,size_y,size_z,size_c,CImg<t>::pixel_type());
      }
      const unsigned int siz = size_x*size_y*size_z*size_c;
      if (values && siz) {
        _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
        try { _data = new T[siz]; } catch (...) {
          _width = _height = _depth = _spectrum = 0; _data = 0;
          throw CImgInstanceException(_cimg_instance
                                      "CImg() : Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                      cimg_instance,
                                      cimg::strbuffersize(size_x*size_y*size_z*size_c*sizeof(T)),size_x,size_y,size_z,size_c);

        }
        const t *ptrs = values + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }
    }

    //! Construct image with specified size and initialize pixel values from a memory buffer \specialization.
    CImg(const T *const values, const unsigned int size_x, const unsigned int size_y=1,
         const unsigned int size_z=1, const unsigned int size_c=1, const bool is_shared=false) {
      const unsigned int siz = size_x*size_y*size_z*size_c;
      if (values && siz) {
        _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; _is_shared = is_shared;
        if (_is_shared) _data = const_cast<T*>(values);
        else {
          try { _data = new T[siz]; } catch (...) {
            _width = _height = _depth = _spectrum = 0; _data = 0;
            throw CImgInstanceException(_cimg_instance
                                        "CImg() : Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                        cimg_instance,
                                        cimg::strbuffersize(size_x*size_y*size_z*size_c*sizeof(T)),size_x,size_y,size_z,size_c);
          }
          std::memcpy(_data,values,siz*sizeof(T)); }
      } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; }
    }

    //! Construct image from an image file.
    /**
       Construct a new image instance with pixels of type \c T, and initialize pixel values with the data read from an image file.
       \param filename : Input image filename.
       \note
       - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it reads the image
         dimensions and pixel values from the specified image file.
       - The recognition of the image file format by %CImg higly depends on the tools installed on your system
         and on the external libraries you used to link your code against.
       - Considered pixel type \c T should better fit the file format specification, or data loss may occur during file load
         (e.g. constructing a \c CImg<unsigned char> from a float-valued image file).
       - A \c CImgIOException is thrown when the specified \c filename cannot be read, or if the file format is not recognized.
       \par Sample code :
       \code
       const CImg<float> img("reference.jpg");
       img.display();
       \endcode
       \image html ref_image.jpg
       \sa CImg(unsigned int,unsigned int,unsigned int,unsigned int),
           assign(const char*).
    **/
    explicit CImg(const char *const filename):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
      assign(filename);
    }

    //! Copy constructor.
    /**
       Construct a new image instance with pixels of type \c T, as a copy of an existing \c CImg<t> instance.
       \param img : Input image to copy.
       \note
       - Constructed copy has the same size width() x height() x depth() x spectrum() and pixel values as the input image \c img.
       - If input image \c img is \e shared and if types \c T and \c t are the same, the constructed copy is also \e shared,
         and shares its pixel buffer with \c img.
         Modifying a pixel value in the constructed copy will thus also modifies it in the input image \c img.
         This behavior is needful to allow functions to return shared images.
       - Otherwise, the constructed copy allocates its own pixel buffer, and copies pixel values from the input image \c img
         into its buffer. The copied pixel values may be eventually statically casted if types \c T and \c t are different.
       - Constructing a copy from an image \c img when types \c t and \c T are the same is significantly faster than with different types.
       - A \c CImgInstanceException is thrown when the pixel buffer cannot be allocated (e.g. not enough available memory).
       \sa CImg(const CImg<t>&,bool),
           assign(const CImg<t>&),
    **/
    template<typename t>
    CImg(const CImg<t>& img):_is_shared(false) {
      const unsigned int siz = img.size();
      if (img._data && siz) {
        _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum;
        try { _data = new T[siz]; } catch (...) {
          _width = _height = _depth = _spectrum = 0; _data = 0;
          throw CImgInstanceException(_cimg_instance
                                      "CImg() : Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                      cimg_instance,
                                      cimg::strbuffersize(img._width*img._height*img._depth*img._spectrum*sizeof(T)),
                                      img._width,img._height,img._depth,img._spectrum);
        }
        const t *ptrs = img._data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }
    }

    //! Copy constructor \specialization.
    CImg(const CImg<T>& img) {
      const unsigned int siz = img.size();
      if (img._data && siz) {
        _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum; _is_shared = img._is_shared;
        if (_is_shared) _data = const_cast<T*>(img._data);
        else {
          try { _data = new T[siz]; } catch (...) {
            _width = _height = _depth = _spectrum = 0; _data = 0;
            throw CImgInstanceException(_cimg_instance
                                        "CImg() : Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                        cimg_instance,
                                        cimg::strbuffersize(img._width*img._height*img._depth*img._spectrum*sizeof(T)),
                                        img._width,img._height,img._depth,img._spectrum);

          }
          std::memcpy(_data,img._data,siz*sizeof(T));
        }
      } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; }
    }

    //! Advanced copy constructor.
    /**
       Construct a new image instance with pixels of type \c T, as a copy of an existing \c CImg<t> instance,
       while forcing the shared state of the constructed copy.
       \param img : Input image to copy.
       \param is_shared : Desired shared state of the constructed copy.
       \note
       - Similar to CImg(const CImg<t>&), except that it allows to decide the shared state of
         the constructed image, which does not depend anymore on the shared state of the input image \c img :
         - If \c is_shared is \c true, the constructed copy will share its pixel buffer with the input image \c img.
           For that case, the pixel types \c T and \c t \e must be the same.
         - If \c is_shared is \c false, the constructed copy will allocate its own pixel buffer, whether the input image \c img is
           shared or not.
       - A \c CImgArgumentException is thrown when a shared copy is requested with different pixel types \c T and \c t.
       \sa CImg(const CImg<t>&),
           assign(const CImg<t>&,bool).
    **/
    template<typename t>
    CImg(const CImg<t>& img, const bool is_shared):_is_shared(false) {
      if (is_shared) {
        _width = _height = _depth = _spectrum = 0; _data = 0;
        throw CImgArgumentException(_cimg_instance
                                    "CImg() : Invalid construction request of a shared instance from a "
                                    "CImg<%s> image (%u,%u,%u,%u,%p) (pixel types are different).",
                                    cimg_instance,
                                    CImg<t>::pixel_type(),img._width,img._height,img._depth,img._spectrum,img._data);
      }
      const unsigned int siz = img.size();
      if (img._data && siz) {
        _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum;
        try { _data = new T[siz]; } catch (...) {
          _width = _height = _depth = _spectrum = 0; _data = 0;
          throw CImgInstanceException(_cimg_instance
                                      "CImg() : Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                      cimg_instance,
                                      cimg::strbuffersize(img._width*img._height*img._depth*img._spectrum*sizeof(T)),
                                      img._width,img._height,img._depth,img._spectrum);
        }
        const t *ptrs = img._data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
      } else { _width = _height = _depth = _spectrum = 0; _data = 0; }
    }

    //! Advanced copy constructor \specialization.
    CImg(const CImg<T>& img, const bool is_shared) {
      const unsigned int siz = img.size();
      if (img._data && siz) {
        _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum; _is_shared = is_shared;
        if (_is_shared) _data = const_cast<T*>(img._data);
        else {
          try { _data = new T[siz]; } catch (...) {
            _width = _height = _depth = _spectrum = 0; _data = 0;
            throw CImgInstanceException(_cimg_instance
                                        "CImg() : Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                        cimg_instance,
                                        cimg::strbuffersize(img._width*img._height*img._depth*img._spectrum*sizeof(T)),
                                        img._width,img._height,img._depth,img._spectrum);
          }
          std::memcpy(_data,img._data,siz*sizeof(T));
        }
      } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; }
    }

    //! Construct image with dimensions borrowed from another image.
    /**
       Construct a new image instance with pixels of type \c T, and size get from some dimensions of an existing \c CImg<t> instance.
       \param img : Input image from which dimensions are borrowed.
       \param dimensions : String describing the image size along the X,Y,Z and C-dimensions.
       \note
       - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it takes the image dimensions
         (\e not its pixel values) from an existing \c CImg<t> instance.
       - The allocated pixel buffer is \e not filled with a default value, and is likely to contain garbage values.
         In order to initialize pixel values (e.g. with \c 0), use constructor CImg(const CImg<t>&,const char*,T) instead.
       \par Sample code :
       \code
       const CImg<float> img1(256,128,1,3),      // 'img1' is a 256x128x1x3 image.
                         img2(img1,"xyzc"),      // 'img2' is a 256x128x1x3 image.
                         img3(img1,"y,x,z,c"),   // 'img3' is a 128x256x1x3 image.
                         img4(img1,"c,x,y,3",0), // 'img4' is a 3x128x256x3 image (with pixels initialized to '0').
       \endcode
       \sa CImg(unsigned int,unsigned int,unsigned int,unsigned int),
           CImg(const CImg<t>&,const char*,T),
           assign(const CImg<t>&,const char*).
     **/
    template<typename t>
    CImg(const CImg<t>& img, const char *const dimensions):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
      assign(img,dimensions);
    }

    //! Construct image with dimensions borrowed from another image and initialize pixel values.
    /**
       Construct a new image instance with pixels of type \c T, and size get from the dimensions of an existing \c CImg<t> instance,
       and set all pixel values to specified \c value.
       \param img : Input image from which dimensions are borrowed.
       \param dimensions : String describing the image size along the X,Y,Z and V-dimensions.
       \param value : Value used for initialization.
       \note
       - Similar to CImg(const CImg<t>&,const char*), but it also fills the pixel buffer with the specified \c value.
       \sa CImg(unsigned int,unsigned int,unsigned int,unsigned int,T),
           CImg(const CImg<t>&,const char*),
           assign(const CImg<t>&,const char*,T).
     **/
    template<typename t>
    CImg(const CImg<t>& img, const char *const dimensions, const T value):
      _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
      assign(img,dimensions).fill(value);
    }

    //! Construct image from a display window.
    /**
       Construct a new image instance with pixels of type \c T, as a snapshot of an existing \c CImgDisplay instance.
       \param disp : Input display window.
       \note
       - The width() and height() of the constructed image instance are the same as the specified \c CImgDisplay.
       - The depth() and spectrum() of the constructed image instance are respectively set to \c 1 and \c 3 (i.e. a 2d color image).
       - The image pixels are read as 8-bits RGB values.
       \sa CImgDisplay,
           assign(const CImgDisplay&).
     **/
    explicit CImg(const CImgDisplay &disp):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
      disp.snapshot(*this);
    }

    //! In-place version of the default constructor/destructor.
    /**
       In-place version of the default constructor CImg(). It simply resets the instance to an empty image.
       \note
       - It reinitializes the current image instance to a new constructed image instance.
       - Memory used by the previous pixel buffer of the image instance is deallocated if necessary (i.e. if instance was not empty nor shared).
       - If the image instance was shared, it is replaced by a (non-shared) empty image without a deallocation process.
       - It can be useful to force memory deallocation of a pixel buffer used by an image instance, before its formal destruction.
       \sa CImg(),
           ~CImg().
    **/
    CImg<T>& assign() {
      if (!_is_shared) delete[] _data;
      _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0;
      return *this;
    }

    //! In-place version of a constructor.
    /**
       In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int).
       \param size_x : Desired image width().
       \param size_y : Desired image height().
       \param size_z : Desired image depth().
       \param size_c : Desired image spectrum().
       \note
       - It reinitializes the current image instance to a new constructed image instance.
       \sa assign(unsigned int,unsigned int,unsigned int,unsigned int,T).
           CImg(unsigned int,unsigned int,unsigned int,unsigned int).
    **/
    CImg<T>& assign(const unsigned int size_x, const unsigned int size_y=1, const unsigned int size_z=1, const unsigned int size_c=1) {
      const unsigned int siz = size_x*size_y*size_z*size_c;
      if (!siz) return assign();
      const unsigned int curr_siz = size();
      if (siz!=curr_siz) {
        if (_is_shared)
          throw CImgArgumentException(_cimg_instance
                                      "assign() : Invalid assignement request of shared instance from specified image (%u,%u,%u,%u).",
                                      cimg_instance,
                                      size_x,size_y,size_z,size_c);
        else {
          delete[] _data;
          try { _data = new T[siz]; } catch (...) {
            _width = _height = _depth = _spectrum = 0; _data = 0;
            throw CImgInstanceException(_cimg_instance
                                        "assign() : Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                        cimg_instance,
                                        cimg::strbuffersize(size_x*size_y*size_z*size_c*sizeof(T)),size_x,size_y,size_z,size_c);
          }
        }
      }
      _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
      return *this;
    }

    //! In-place version of a constructor.
    /**
       In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,T).
       \param size_x : Desired image width().
       \param size_y : Desired image height().
       \param size_z : Desired image depth().
       \param size_c : Desired image spectrum().
       \param value : Value for initialization.
       \note
       - It reinitializes the current image instance to a new constructed image instance.
       \sa assign(unsigned int,unsigned int,unsigned int,unsigned int),
           CImg(unsigned int,unsigned int,unsigned int,unsigned int,T).
    **/
    CImg<T>& assign(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, const T value) {
      return assign(size_x,size_y,size_z,size_c).fill(value);
    }

    //! In-place version of a constructor.
    /**
       In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,int,int,...).
       \param size_x : Desired image width().
       \param size_y : Desired image height().
       \param size_z : Desired image depth().
       \param size_c : Desired image spectrum().
       \param value0 : First value of the initialization sequence (must be an integer).
       \param value1 : Second value of the initialization sequence (must be an integer).
       \param ...
       \note
       - It reinitializes the current image instance to a new constructed image instance.
       \sa assign(unsigned int,unsigned int,unsigned int,unsigned int,double,double,...),
           CImg(unsigned int,unsigned int,unsigned int,unsigned int,int,int,...).
    **/
    CImg<T>& assign(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,
                    const int value0, const int value1, ...) {
      assign(size_x,size_y,size_z,size_c);
      _CImg_stdarg(*this,value0,value1,size_x*size_y*size_z*size_c,int);
      return *this;
    }

    //! In-place version of a constructor.
    /**
       In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,double,double,...).
       \param size_x : Desired image width().
       \param size_y : Desired image height().
       \param size_z : Desired image depth().
       \param size_c : Desired image spectrum().
       \param value0 : First value of the initialization sequence (must be a double).
       \param value1 : Second value of the initialization sequence (must be a double).
       \param ...
       \note
       - It reinitializes the current image instance to a new constructed image instance.
       \sa assign(unsigned int,unsigned int,unsigned int,unsigned int,int,int,...),
           CImg(unsigned int,unsigned int,unsigned int,unsigned int,double,double,...).
    **/
    CImg<T>& assign(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,
                    const double value0, const double value1, ...) {
      assign(size_x,size_y,size_z,size_c);
      _CImg_stdarg(*this,value0,value1,size_x*size_y*size_z*size_c,double);
      return *this;
    }

    //! In-place version of a constructor.
    /**
       In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,const char*,bool).
       \param size_x : Desired image width().
       \param size_y : Desired image height().
       \param size_z : Desired image depth().
       \param size_c : Desired image spectrum().
       \param values : Value string describing the way pixel values are set.
       \param repeat_values : Flag telling if filling process is periodic.
       \note
       - It reinitializes the current image instance to a new constructed image instance.
       \sa CImg(unsigned int,unsigned int,unsigned int,unsigned int,const char*,bool).
    **/
    CImg<T>& assign(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c,
                    const char *const values, const bool repeat_values) {
      return assign(size_x,size_y,size_z,size_c).fill(values,repeat_values);
    }

    //! In-place version of a constructor.
    /**
       In-place version of the constructor CImg(const t*,unsigned int,unsigned int,unsigned int,unsigned int,bool).
       \param values : Pointer to the input memory buffer.
       \param size_x : Desired image width().
       \param size_y : Desired image height().
       \param size_z : Desired image depth().
       \param size_c : Desired image spectrum().
       \note
       - It reinitializes the current image instance to a new constructed image instance.
       \sa assign(const t*,unsigned int,unsigned int,unsigned int,unsigned int,bool).
           CImg(const t*,unsigned int,unsigned int,unsigned int,unsigned int,bool).
    **/
    template<typename t>
    CImg<T>& assign(const t *const values, const unsigned int size_x, const unsigned int size_y=1,
                    const unsigned int size_z=1, const unsigned int size_c=1) {
      const unsigned int siz = size_x*size_y*size_z*size_c;
      if (!values || !siz) return assign();
      assign(size_x,size_y,size_z,size_c);
      const t *ptrs = values + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
      return *this;
    }

    //! In-place version of a constructor \specialization.
    CImg<T>& assign(const T *const values, const unsigned int size_x, const unsigned int size_y=1,
                    const unsigned int size_z=1, const unsigned int size_c=1) {
      const unsigned int siz = size_x*size_y*size_z*size_c;
      if (!values || !siz) return assign();
      const unsigned int curr_siz = size();
      if (values==_data && siz==curr_siz) return assign(size_x,size_y,size_z,size_c);
      if (_is_shared || values+siz<_data || values>=_data+size()) {
        assign(size_x,size_y,size_z,size_c);
        if (_is_shared) std::memmove(_data,values,siz*sizeof(T));
        else std::memcpy(_data,values,siz*sizeof(T));
      } else {
        T *new_data = 0;
        try { new_data = new T[siz]; } catch (...) {
          _width = _height = _depth = _spectrum = 0; _data = 0;
          throw CImgInstanceException(_cimg_instance
                                      "assign() : Failed to allocate memory (%s) for image (%u,%u,%u,%u).",
                                      cimg_instance,
                                      cimg::strbuffersize(size_x*size_y*size_z*size_c*sizeof(T)),size_x,size_y,size_z,size_c);
        }
        std::memcpy(new_data,values,siz*sizeof(T));
        delete[] _data; _data = new_data; _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c;
      }
      return *this;
    }

    //! In-place version of a constructor.
    /**
       In-place version of the constructor CImg(const t*,unsigned int,unsigned int,unsigned int,unsigned int,bool).
       \param values : Pointer to the input memory buffer.
       \param size_x : Desired image width().
       \param size_y : Desired image height().
       \param size_z : Desired image depth().
       \param size_c : Desired image spectrum().
       \param is_shared : Flag telling if input memory buffer must be shared by the current instance.
       \note
       - It reinitializes the current image instance to a new constructed image instance.
       \sa assign(const t*,unsigned int,unsigned int,unsigned int,unsigned int).
           CImg(const t*,unsigned int,unsigned int,unsigned int,unsigned int,bool).
    **/
    template<typename t>
    CImg<T>& assign(const t *const values, const unsigned int size_x, const unsigned int size_y,
                    const unsigned int size_z, const unsigned int size_c, const bool is_shared) {
      if (is_shared)
        throw CImgArgumentException(_cimg_instance
                                    "assign() : Invalid assignment request of shared instance from (%s*) buffer"
                                    "(pixel types are different).",
                                    cimg_instance,
                                    CImg<t>::pixel_type());
      return assign(values,size_x,size_y,size_z,size_c);
    }

    //! In-place version of a constructor \specialization.
    CImg<T>& assign(const T *const values, const unsigned int size_x, const unsigned int size_y,
                    const unsigned int size_z, const unsigned int size_c, const bool is_shared) {
      const unsigned int siz = size_x*size_y*size_z*size_c;
      if (!values || !siz) {
        if (is_shared)
          throw CImgArgumentException(_cimg_instance
                                      "assign() : Invalid assignment request of shared instance from (null) or empty buffer.",
                                      cimg_instance);
        else return assign();
      }
      if (!is_shared) { if (_is_shared) assign(); assign(values,size_x,size_y,size_z,size_c); }
      else {
        if (!_is_shared) {
          if (values+siz<_data || values>=_data+size()) assign();
          else cimg::warn(_cimg_instance
                          "assign() : Shared image instance has overlapping memory.",
                          cimg_instance);
        }
        _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; _is_shared = true;
        _data = const_cast<T*>(values);
      }
      return *this;
    }

    //! In-place version of a constructor.
    /**
       In-place version of the constructor CImg(const char*).
       \param filename : Input image filename.
       \note
       - It reinitializes the current image instance to a new constructed image instance.
       - Equivalent to load(const char*).
       \sa CImg(const char*),
           load(const char*).
    **/
    CImg<T>& assign(const char *const filename) {
      return load(filename);
    }

    //! In-place version of the default copy constructor.
    /**
       In-place version of the constructor CImg(const CImg<t>&).
       \param img : Input image to copy.
       \note
       - It reinitializes the current image instance to a new constructed image instance.
       \sa assign(const CImg<t>&,bool),
           CImg(const CImg<t>&).
    **/
    template<typename t>
    CImg<T>& assign(const CImg<t>& img) {
      return assign(img._data,img._width,img._height,img._depth,img._spectrum);
    }

    //! In-place version of the advanced copy constructor.
    /**
       In-place version of the constructor CImg(const CImg<t>&,bool).
       \param img : Input image to copy.
       \param is_shared : Desired shared state of the constructed copy.
       \sa assign(const CImg<t>&),
           CImg(const CImg<t>&,bool).
     **/
    template<typename t>
    CImg<T>& assign(const CImg<t>& img, const bool is_shared) {
      return assign(img._data,img._width,img._height,img._depth,img._spectrum,is_shared);
    }

    //! In-place version of a constructor.
    /**
       In-place version of the constructor CImg(const CImg<t>&,const char*).
       \param img : Input image from which dimensions are borrowed.
       \param dimensions : String describing the image size along the X,Y,Z and V-dimensions.
       \note
       - It reinitializes the current image instance to a new constructed image instance.
       \sa assign(const CImg<t>&,const char*,T),
           CImg(const CImg<t>&,const char*).
     **/
    template<typename t>
    CImg<T>& assign(const CImg<t>& img, const char *const dimensions) {
      if (!dimensions || !*dimensions) return assign(img._width,img._height,img._depth,img._spectrum);
      unsigned int siz[4] = { 0,1,1,1 }, k = 0;
      for (const char *s = dimensions; *s && k<4; ++k) {
        char item[256] = { 0 };
        if (std::sscanf(s,"%255[^0-9%xyzvwhdcXYZVWHDC]",item)>0) s+=std::strlen(item);
        if (*s) {
          unsigned int val = 0; char sep = 0;
          if (std::sscanf(s,"%u%c",&val,&sep)>0) {
            if (sep=='%') siz[k] = val*(k==0?_width:k==1?_height:k==2?_depth:_spectrum)/100;
            else siz[k] = val;
            while (*s>='0' && *s<='9') ++s; if (sep=='%') ++s;
          } else switch (cimg::uncase(*s)) {
          case 'x' : case 'w' : siz[k] = img._width; ++s; break;
          case 'y' : case 'h' : siz[k] = img._height; ++s; break;
          case 'z' : case 'd' : siz[k] = img._depth; ++s; break;
          case 'c' : case 's' : siz[k] = img._spectrum; ++s; break;
          default :
            throw CImgArgumentException(_cimg_instance
                                        "assign() : Invalid character '%c' detected in specified dimension string '%s'.",
                                        cimg_instance,
                                        *s,dimensions);
          }
        }
      }
      return assign(siz[0],siz[1],siz[2],siz[3]);
    }

    //! In-place version of a constructor.
    /**
       In-place version of the constructor CImg(const CImg<t>&,const char*,T).
       \param img : Input image from which dimensions are borrowed.
       \param dimensions : String describing the image size along the X,Y,Z and V-dimensions.
       \param value : Value for initialization.
       \note
       - It reinitializes the current image instance to a new constructed image instance.
       \sa assign(const CImg<t>&,const char*),
           CImg(const CImg<t>&,const char*,T).
     **/
    template<typename t>
    CImg<T>& assign(const CImg<t>& img, const char *const dimensions, const T value) {
      return assign(img,dimensions).fill(value);
    }

    //! In-place version of a constructor.
    /**
       In-place version of the constructor CImg(const CImgDisplay&).
       \param disp : Input \c CImgDisplay.
       \note
       - It reinitializes the current image instance to a new constructed image instance.
       \sa CImg(const CImgDisplay&).
    **/
    CImg<T>& assign(const CImgDisplay &disp) {
      disp.snapshot(*this);
      return *this;
    }

    //! In-place version of the default constructor.
    /**
       Equivalent to assign().
       \note
       - It has been defined for compatibility with STL naming conventions.
       \sa assign().
    **/
    CImg<T>& clear() {
      return assign();
    }

    //! Transfer content of an image instance into another one.
    /**
       Transfer the dimensions and the pixel buffer content of an image instance into another one,
       and replace instance by an empty image. It avoids the copy of the pixel buffer
       when possible.
       \param img : Destination image.
       \note
       - Pixel types \c T and \c t of source and destination images can be different, though the process is designed to be
         instantaneous when \c T and \c t are the same.
       \par Sample code :
       \code
       CImg<float> src(256,256,1,3,0), // Construct a 256x256x1x3 (color) image filled with value '0'.
                   dest(16,16);        // Construct a 16x16x1x1 (scalar) image.
       src.move_to(dest);              // Now, 'src' is empty and 'dest' is the 256x256x1x3 image.
       \endcode
       \sa move_to(CImgList<t>&,unsigned int),
           swap(CImg<T>&).
    **/
    template<typename t>
    CImg<t>& move_to(CImg<t>& img) {
      img.assign(*this);
      assign();
      return img;
    }

    //! Transfer content of an image instance into another one \specialization.
    CImg<T>& move_to(CImg<T>& img) {
      if (_is_shared || img._is_shared) img.assign(*this);
      else swap(img);
      assign();
      return img;
    }

    //! Transfer content of an image instance into a new image in an image list.
    /**
       Transfer the dimensions and the pixel buffer content of an image instance
       into a newly inserted image at position \c pos in specified \c CImgList<t> instance.
       \param list : Destination list.
       \param pos : Position of the newly inserted image in the list.
       \note
       - When optionnal parameter \c pos is ommited, the image instance is transfered as a new
         image at the end of the specified \c list.
       - It is convenient to sequentially insert new images into image lists, with no
         additional copies of memory buffer.
       \par Sample code :
       \code
       CImgList<float> list;             // Construct an empty image list.
       CImg<float> img("reference.jpg"); // Read image from filename.
       img.move_to(list);                // Transfer image content as a new item in the list (no buffer copy).
       \endcode
       \sa move_to(CImg<t>&),
           swap(CImg<T>&).
    **/
    template<typename t>
    CImgList<t>& move_to(CImgList<t>& list, const unsigned int pos=~0U) {
      const unsigned int npos = pos>list._width?list._width:pos;
      move_to(list.insert(1,npos)[npos]);
      return list;
    }

    //! Swap fields of two image instances.
    /**
      \param img : Image to swap fields with.
      \note
      - It can be used to interchange the content of two images in a very fast way. Can be convenient when dealing
        with algorithms requiring two swapping buffers.
      \par Sample code :
      \code
      CImg<float> img1("lena.jpg"),
                  img2("milla.jpg");
      img1.swap(img2);               // Now, 'img1' is 'milla' and 'img2' is 'lena'.
      \endcode
    **/
    CImg<T>& swap(CImg<T>& img) {
      cimg::swap(_width,img._width);
      cimg::swap(_height,img._height);
      cimg::swap(_depth,img._depth);
      cimg::swap(_spectrum,img._spectrum);
      cimg::swap(_data,img._data);
      cimg::swap(_is_shared,img._is_shared);
      return img;
    }

    //! Get a reference to an empty image.
    /**
       \note
       This function is useful mainly to declare optional parameters having type \c CImg<T> in functions prototypes, e.g.
       \code
       void f(const int x=0, const int y=0, const CImg<float>& img=CImg<float>::empty());
       \endcode
     **/
    static CImg<T>& empty() {
      static CImg<T> _empty;
      return _empty.assign();
    }

    //@}
    //------------------------------------------
    //
    //! \name Overloaded Operators
    //@{
    //------------------------------------------

    //! Access to a pixel value.
    /**
       Return a reference to a located pixel value of the image instance,
       being possibly \e const, whether the image instance is \e const or not.
       This is the standard method to get/set pixel values in \c CImg<T> images.
       \param x : X-coordinate of the pixel value.
       \param y : Y-coordinate of the pixel value.
       \param z : Z-coordinate of the pixel value.
       \param c : C-coordinate of the pixel value.
       \note
       - Range of pixel coordinates start from <tt>(0,0,0,0)</tt> to <tt>(width()-1,height()-1,depth()-1,spectrum()-1)</tt>.
       - Due to the particular arrangement of the pixel buffers defined in %CImg, you can omit one coordinate if the corresponding dimension
         is equal to \c 1.
         For instance, pixels of a 2d image (depth() equal to \c 1) can be accessed by <tt>img(x,y,c)</tt> instead of <tt>img(x,y,0,c)</tt>.
       \warning
       - There is \e no boundary checking done in this operator, to make it as fast as possible.
         You \e must take care of out-of-bounds access by yourself, if necessary.
         For debuging purposes, you may want to define macro \c 'cimg_verbosity'>=3 to enable additional boundary checking operations
         in this operator. In that case, warning messages will be printed on the error output when accessing out-of-bounds pixels.
       \par Sample code :
       \code
       CImg<float> img(100,100,1,3,0);                   // Construct a 100x100x1x3 (color) image with pixels set to '0'.
       const float
          valR = img(10,10,0,0),                         // Read red value at coordinates (10,10).
          valG = img(10,10,0,1),                         // Read green value at coordinates (10,10)
          valB = img(10,10,2),                           // Read blue value at coordinates (10,10) (Z-coordinate can be omitted).
          avg = (valR + valG + valB)/3;                  // Compute average pixel value.
       img(10,10,0) = img(10,10,1) = img(10,10,2) = avg; // Replace the color pixel (10,10) by the average grey value.
       \endcode
       \sa at(),
           atX(),
           atXY(),
           atXYZ(),
           atXYZC().
    **/
#if cimg_verbosity>=3
    T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) {
      const unsigned int off = (unsigned int)offset(x,y,z,c);
      if (!_data || off>=size()) {
        cimg::warn(_cimg_instance
                   "operator() : Invalid pixel request, at coordinates (%u,%u,%u,%u) [offset=%u].",
                   cimg_instance,
                   x,y,z,c,off);
        return *_data;
      }
      else return _data[off];
    }

    //! Access to a pixel value \const.
    const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const {
      return const_cast<CImg<T>*>(this)->operator()(x,y,z,c);
    }

    //! Access to a pixel value.
    /**
       \param x : X-coordinate of the pixel value.
       \param y : Y-coordinate of the pixel value.
       \param z : Z-coordinate of the pixel value.
       \param c : C-coordinate of the pixel value.
       \param wh : Precomputed offset, must be equal to <tt>width()*\ref height()</tt>.
       \param whd : Precomputed offset, must be equal to <tt>width()*\ref height()*\ref depth()</tt>.
       \note
       - Similar to (but faster than) operator()().
         It uses precomputed offsets to optimize memory access. You may use it to optimize
         the reading/writing of several pixel values in the same image (e.g. in a loop).
       \sa operator()().
     **/
    T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c,
                  const unsigned long wh, const unsigned long whd=0) {
      cimg::unused(wh,whd);
      return (*this)(x,y,z,c);
    }

    //! Access to a pixel value \const.
    const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c,
                        const unsigned long wh, const unsigned long whd=0) const {
      cimg::unused(wh,whd);
      return (*this)(x,y,z,c);
    }
#else
    T& operator()(const unsigned int x) {
      return _data[x];
    }

    const T& operator()(const unsigned int x) const {
      return _data[x];
    }

    T& operator()(const unsigned int x, const unsigned int y) {
      return _data[x + y*_width];
    }

    const T& operator()(const unsigned int x, const unsigned int y) const {
      return _data[x + y*_width];
    }

    T& operator()(const unsigned int x, const unsigned int y, const unsigned int z) {
      return _data[x + y*_width + z*_width*_height];
   }

    const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z) const {
      return _data[x + y*_width + z*_width*_height];
    }

    T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c) {
      return _data[x + y*_width + z*_width*_height + c*_width*_height*_depth];
    }

    const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c) const {
      return _data[x + y*_width + z*_width*_height + c*_width*_height*_depth];
    }

    T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int,
                  const unsigned long wh) {
      return _data[x + y*_width + z*wh];
    }

    const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int,
                        const unsigned long wh) const {
      return _data[x + y*_width + z*wh];
    }

    T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c,
                  const unsigned long wh, const unsigned long whd) {
      return _data[x + y*_width + z*wh + c*whd];
    }

    const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c,
                        const unsigned long wh, const unsigned long whd) const {
      return _data[x + y*_width + z*wh + c*whd];
    }
#endif

    //! Implicitely cast an image into a \c T*.
    /**
       Implicitely cast a \c CImg<T> instance into a \c T* or \c const \c T* pointer, whether the image instance
       is \e const or not. The returned pointer points on the first value of the image pixel buffer.
       \note
       - It simply returns the pointer data() to the pixel buffer.
       - This implicit conversion is convenient to test the empty state of images (data() being \c 0 in this case), e.g.
       \code
       CImg<float> img1(100,100), img2; // 'img1' is a 100x100 image, 'img2' is an empty image.
       if (img1) {                      // Test succeeds, 'img1' is not an empty image.
         if (!img2) {                   // Test succeeds, 'img2' is an empty image.
           std::printf("'img1' is not empty, 'img2' is empty.");
         }
       }
       \endcode
       - It also allows to use brackets to access pixel values, without need for a \c CImg<T>::operator[](), e.g.
       \code
       CImg<float> img(100,100);
       const float value = img[99]; // Access to value of the last pixel on the first line.
       img[510] = 255;              // Set pixel value at (10,5).
       \endcode
       \sa operator()().
    **/
    operator T*() {
      return _data;
    }

    //! Implicitely cast an image into a \c T* \const.
    operator const T*() const {
      return _data;
    }

    //! Assign a value to all image pixels.
    /**
       Assign specified \c value to each pixel value of the image instance.
       \param value : Value that will be assigned to image pixels.
       \note
       - The image size is never modified.
       - The \c value may be casted to pixel type \c T if necessary.
       \par Sample code
       \code
       CImg<char> img(100,100); // Declare image (with garbage values).
       img = 0;                 // Set all pixel values to '0'.
       img = 1.2;               // Set all pixel values to '1' (cast of '1.2' as a 'char').
       \endcode
       \sa fill(const T).
    **/
    CImg<T>& operator=(const T value) {
      return fill(value);
    }

    //! Assign pixels values from a specified expression.
    /**
       Initialize all pixel values from the specified string \c expression.
       \param expression : Value string describing the way pixel values are set.
       \note
       - String parameter \c expression may describe different things :
         - If \c expression is a list of values (as in \c "1,2,3,8,3,2"), or a formula (as in \c "(x*y)%255"),
           the pixel values are set from specified \c expression and the image size is not modified.
         - If \c expression is a filename (as in \c "reference.jpg"), the corresponding image file is loaded and replace the image instance.
           The image size is modified if necessary.
       \par Sample code :
       \code
       CImg<float> img1(100,100), img2(img1), img3(img1); // Declare three 100x100 scalar images with unitialized pixel values.
       img1 = "0,50,100,150,200,250,200,150,100,50";      // Set pixel values of 'img1' from a value sequence.
       img2 = "10*((x*y)%25)";                            // Set pixel values of 'img2' from a formula.
       img3 = "reference.jpg";                            // Set pixel values of 'img3' from a file (image size is modified).
       (img1,img2,img3).display();
       \endcode
       \image html ref_operator_eq.jpg
       \sa fill(const char*, bool),
           load(const char*).
    **/
    CImg<T>& operator=(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        fill(expression,true);
      } catch (CImgException&) {
        cimg::exception_mode() = omode;
        load(expression);
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    //! Copy an image into the current image instance.
    /**
       Similar to the in-place copy constructor assign(const CImg<t>&).
    **/
    template<typename t>
    CImg<T>& operator=(const CImg<t>& img) {
      return assign(img);
    }

    //! Copy an image into the current image instance \specialization.
    CImg<T>& operator=(const CImg<T>& img) {
      return assign(img);
    }

    //! Copy the content of a display window to the current image instance.
    /**
       Similar to assign(const CImgDisplay&).
    **/
    CImg<T>& operator=(const CImgDisplay& disp) {
      disp.snapshot(*this);
      return *this;
    }

    //! In-place addition operator.
    /**
       Add specified \c value to all pixels of an image instance.
       \param value : Value to add.
       \note
       - Resulting pixel values are casted to fit the pixel type \c T. For instance, adding \c 0.2 to a \c CImg<char> is possible but does nothing indeed.
       - Overflow values are treated as with standard C++ numeric types. For instance,
       \code
       CImg<unsigned char> img(100,100,1,1,255); // Construct a 100x100 image with pixel values '255'.
       img+=1;                                   // Add '1' to each pixels -> Overflow.
       // here all pixels of image 'img' are equal to '0'.
       \endcode
       - To prevent value overflow, you may want to consider pixel type \c T as \c float or \c double, and use cut() after addition.
       \par Sample code :
       \code
       CImg<unsigned char> img1("reference.jpg");          // Load a 8-bits RGB image (values in [0,255]).
       CImg<float> img2(img1);                             // Construct a float-valued copy of 'img1'.
       img2+=100;                                          // Add '100' to pixel values -> goes out of [0,255] but no problems with floats.
       img2.cut(0,255);                                    // Cut values in [0,255] to fit the 'unsigned char' constraint.
       img1 = img2;                                        // Rewrite safe result in 'unsigned char' version 'img1'.
       const CImg<unsigned char> img3 = (img1 + 100).cut(0,255); // Do the same in a more simple and elegant way.
       (img1,img2,img3).display();
       \endcode
       \image html ref_operator_plus.jpg
       \sa operator+(const t) const,
           operator-=(const t),
           operator*=(const t),
           operator/=(const t),
           operator%=(const t),
           operator&=(const t),
           operator|=(const t),
           operator^=(const t),
           operator<<=(const t),
           operator>>=(const t).
     **/
    template<typename t>
    CImg<T>& operator+=(const t value) {
      cimg_for(*this,ptrd,T) *ptrd = (T)(*ptrd + value);
      return *this;
    }

    //! In-place addition operator.
    /**
       Add values to image pixels, according to the specified string \c expression.
       \param expression : Value string describing the way pixel values are added.
       \note
       - Similar to operator=(const char*), except that it adds values to the pixels of the current image instance,
         instead of assigning them.
       \sa operator+=(const t),
           operator=(const char*),
           operator+(const char*) const,
           operator-=(const char*),
           operator*=(const char*),
           operator/=(const char*),
           operator%=(const char*),
           operator&=(const char*),
           operator|=(const char*),
           operator^=(const char*),
           operator<<=(const char*),
           operator>>=(const char*).
    **/
    CImg<T>& operator+=(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"operator+=");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd + mp.eval(x,y,z,c)); ++ptrd; }
      } catch (CImgException&) {
        cimg::exception_mode() = omode;
        *this+=CImg<T>(_width,_height,_depth,_spectrum,expression,true);
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    //! In-place addition operator.
    /**
       Add values to image pixels, according to the values of the input image \c img.
       \param img : Input image to add.
       \note
       - The size of the image instance is never modified.
       - It is not mandatory that input image \c img has the same size as the image instance. If less values are available
         in \c img, then the values are added cyclically. For instance, adding one WxH scalar image (spectrum() equal to \c 1) to
         one WxH color image (spectrum() equal to \c 3) means each color channel will be incremented with the same values at the same
         locations.
       \par Sample code :
       \code
       CImg<float> img1("reference.jpg");                                   // Load a RGB color image (img1.spectrum()==3)
       const CImg<float> img2(img1.width(),img.height(),1,1,"255*(x/w)^2"); // Construct a scalar shading (img2.spectrum()==1).
       img1+=img2;                                                          // Add shading to each channel of 'img1'.
       img1.cut(0,255);                                                     // Prevent [0,255] overflow.
       (img2,img1).display();
       \endcode
       \image html ref_operator_plus1.jpg
       \sa operator+(const CImg<t>&) const,
           operator=(const CImg<t>&),
           operator-=(const CImg<t>&),
           operator*=(const CImg<t>&),
           operator/=(const CImg<t>&),
           operator%=(const CImg<t>&),
           operator&=(const CImg<t>&),
           operator|=(const CImg<t>&),
           operator^=(const CImg<t>&),
           operator<<=(const CImg<t>&),
           operator>>=(const CImg<t>&).
    **/
    template<typename t>
    CImg<T>& operator+=(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return *this+=+img;
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)(*ptrd + *(ptrs++));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd + *(ptrs++));
      }
      return *this;
    }

    //! In-place increment operator (prefix).
    /**
       Add \c 1 to all image pixels, and return a reference to the current incremented image instance.
       \note
       - Writing \c ++img is equivalent to \c img+=1.
       \sa operator++(int),
           operator--().
     **/
    CImg<T>& operator++() {
      cimg_for(*this,ptrd,T) ++*ptrd;
      return *this;
    }

    //! In-place increment operator (postfix).
    /**
       Add \c 1 to all image pixels, and return a new copy of the initial (pre-incremented) image instance.
       \note
       - Use the prefixed version operator++() if you don't need a copy of the initial (pre-incremented) image instance, since
         a useless image copy may be expensive in terms of memory usage.
       \sa operator++(),
           operator--(int).
     **/
    CImg<T> operator++(int) {
      const CImg<T> copy(*this,false);
      ++*this;
      return copy;
    }

    //! Get a non-shared copy of the image instance.
    /**
       \note
       - Use this operator to ensure you get a non-shared copy of an image instance with same pixel type \c T.
         Indeed, the usual copy constructor CImg<T>(const CImg<T>&) returns a shared copy of a shared input image, and it may be
         not desirable to work on a regular copy (e.g. for a resize operation) if you have no informations about the shared state
         of the input image.
       - Writing \c (+img) is equivalent to \c CImg<T>(img,false).
       \sa CImg(const CImg<T>&),
           CImg(const CImg<T>&,bool),
           operator-() const,
           operator~() const.
    **/
    CImg<T> operator+() const {
      return CImg<T>(*this,false);
    }

    //! Addition operator.
    /**
       Similar to operator+=(const t), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
     **/
    template<typename t>
    CImg<_cimg_Tt> operator+(const t value) const {
      return CImg<_cimg_Tt>(*this,false)+=value;
    }

    //! Addition operator.
    /**
       Similar to operator+=(const char*), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
     **/
    CImg<Tfloat> operator+(const char *const expression) const {
      return CImg<Tfloat>(*this,false)+=expression;
    }

    //! Addition operator.
    /**
       Similar to operator+=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
     **/
    template<typename t>
    CImg<_cimg_Tt> operator+(const CImg<t>& img) const {
      return CImg<_cimg_Tt>(*this,false)+=img;
    }

    //! In-place substraction operator.
    /**
       Similar to operator+=(const t), except that it performs a substraction instead of an addition.
     **/
    template<typename t>
    CImg<T>& operator-=(const t value) {
      cimg_for(*this,ptrd,T) *ptrd = (T)(*ptrd - value);
      return *this;
    }

    //! In-place substraction operator.
    /**
       Similar to operator+=(const char*), except that it performs a substraction instead of an addition.
     **/
    CImg<T>& operator-=(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"operator-=");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd - mp.eval(x,y,z,c)); ++ptrd; }
      } catch (CImgException&) {
        cimg::exception_mode() = omode;
        *this-=CImg<T>(_width,_height,_depth,_spectrum,expression,true);
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    //! In-place substraction operator.
    /**
       Similar to operator+=(const CImg<t>&), except that it performs a substraction instead of an addition.
     **/
    template<typename t>
    CImg<T>& operator-=(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return *this-=+img;
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)(*ptrd - *(ptrs++));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd - *(ptrs++));
      }
      return *this;
    }

    //! In-place decrement operator (prefix).
    /**
       Similar to operator++(), except that it performs a decrement instead of an increment.
    **/
    CImg<T>& operator--() {
      cimg_for(*this,ptrd,T) *ptrd = *ptrd-(T)1;
      return *this;
    }

    //! In-place decrement operator (postfix).
    /**
       Similar to operator++(int), except that it performs a decrement instead of an increment.
    **/
    CImg<T> operator--(int) {
      const CImg<T> copy(*this,false);
      --*this;
      return copy;
    }

    //! Replace each pixel by its opposite value.
    /**
       \note
       - If the computed opposite values are out-of-range, they are treated as with standard C++ numeric types. For instance,
         the \c unsigned \c char opposite of \c 1 is \c 255.
       \par Sample code :
       \code
       const CImg<unsigned char>
         img1("reference.jpg"),   // Load a RGB color image.
         img2 = -img1;            // Compute its opposite (in 'unsigned char').
       (img1,img2).display();
       \endcode
       \image html ref_operator_minus.jpg
       \sa operator+(),
           operator~().
     **/
    CImg<T> operator-() const {
      return CImg<T>(_width,_height,_depth,_spectrum,(T)0)-=*this;
    }

    //! Substraction operator.
    /**
       Similar to operator-=(const t), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
    **/
    template<typename t>
    CImg<_cimg_Tt> operator-(const t value) const {
      return CImg<_cimg_Tt>(*this,false)-=value;
    }

    //! Substraction operator.
    /**
       Similar to operator-=(const char*), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
    **/
    CImg<Tfloat> operator-(const char *const expression) const {
      return CImg<Tfloat>(*this,false)-=expression;
    }

    //! Substraction operator.
    /**
       Similar to operator-=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
    **/
    template<typename t>
    CImg<_cimg_Tt> operator-(const CImg<t>& img) const {
      return CImg<_cimg_Tt>(*this,false)-=img;
    }

    //! In-place multiplication operator.
    /**
       Similar to operator+=(const t), except that it performs a multiplication instead of an addition.
     **/
    template<typename t>
    CImg<T>& operator*=(const t value) {
      cimg_for(*this,ptrd,T) *ptrd = (T)(*ptrd * value);
      return *this;
    }

    //! In-place multiplication operator.
    /**
       Similar to operator+=(const char*), except that it performs a multiplication instead of an addition.
     **/
    CImg<T>& operator*=(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"operator*=");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd * mp.eval(x,y,z,c)); ++ptrd; }
      } catch (CImgException&) {
        cimg::exception_mode() = omode;
        mul(CImg<T>(_width,_height,_depth,_spectrum,expression,true));
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    //! In-place multiplication operator.
    /**
       Replace the image instance by the matrix multiplication between the image instance and the specified matrix \c img.
       \param img : Second operand of the matrix multiplication.
       \note
       - It does \e not compute a pointwise multiplication between two images. For this purpose, use mul(const CImg<t>&) instead.
       - The size of the image instance can be modified by this operator.
       \par Sample code :
       \code
       CImg<float> A(2,2,1,1, 1,2,3,4);   // Construct 2x2 matrix A = [1,2;3,4].
       const CImg<float> X(1,2,1,1, 1,2); // Construct 1x2 vector X = [1;2].
       A*=X;                              // Assign matrix multiplication A*X to 'A'.
       // 'A' is now a 1x2 vector whose values are [5;11].
       \endcode
       \sa operator*(const CImg<t>&) const,
           mul().
    **/
    template<typename t>
    CImg<T>& operator*=(const CImg<t>& img) {
      return ((*this)*img).move_to(*this);
    }

    //! Multiplication operator.
    /**
       Similar to operator*=(const t), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
    **/
    template<typename t>
    CImg<_cimg_Tt> operator*(const t value) const {
      return CImg<_cimg_Tt>(*this,false)*=value;
    }

    //! Multiplication operator.
    /**
       Similar to operator*=(const char*), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
    **/
    CImg<Tfloat> operator*(const char *const expression) const {
      return CImg<Tfloat>(*this,false)*=expression;
    }

    //! Multiplication operator.
    /**
       Similar to operator*=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
    **/
    template<typename t>
    CImg<_cimg_Tt> operator*(const CImg<t>& img) const {
      if (_width!=img._height || _depth!=1 || _spectrum!=1)
        throw CImgArgumentException(_cimg_instance
                                    "operator*() : Invalid multiplication of instance by specified matrix (%u,%u,%u,%u,%p)",
                                    cimg_instance,
                                    img._width,img._height,img._depth,img._spectrum,img._data);

      CImg<_cimg_Tt> res(img._width,_height);
      _cimg_Tt value, *ptrd = res._data;
#ifdef cimg_use_openmp
#pragma omp parallel for if (size()>=1000 && img.size()>=1000) private(value)
#endif
      cimg_forXY(res,i,j) { value = 0; cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); *(ptrd++) = value; }
      return res;
    }

    //! In-place division operator.
    /**
       Similar to operator+=(const t), except that it performs a division instead of an addition.
     **/
    template<typename t>
    CImg<T>& operator/=(const t value) {
      cimg_for(*this,ptrd,T) *ptrd = (T)(*ptrd / value);
      return *this;
    }

    //! In-place division operator.
    /**
       Similar to operator+=(const char*), except that it performs a division instead of an addition.
     **/
    CImg<T>& operator/=(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"operator/=");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd / mp.eval(x,y,z,c)); ++ptrd; }
      } catch (CImgException&) {
        cimg::exception_mode() = omode;
        div(CImg<T>(_width,_height,_depth,_spectrum,expression,true));
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    //! In-place division operator.
    /**
       Replace the image instance by the (right) matrix division between the image instance and the specified matrix \c img.
       \param img : Second operand of the matrix division.
       \note
       - It does \e not compute a pointwise division between two images. For this purpose, use div(const CImg<t>&) instead.
       - It returns the matrix operation \c A*inverse(img).
       - The size of the image instance can be modified by this operator.
       \sa operator/(const CImg<t>&) const,
           operator*(const CImg<t>&) const,
           div().
     **/
    template<typename t>
    CImg<T>& operator/=(const CImg<t>& img) {
      return (*this*img.get_invert()).move_to(*this);
    }

    //! Division operator.
    /**
       Similar to operator/=(const t), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
    **/
    template<typename t>
    CImg<_cimg_Tt> operator/(const t value) const {
      return CImg<_cimg_Tt>(*this,false)/=value;
    }

    //! Division operator.
    /**
       Similar to operator/=(const char*), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
    **/
    CImg<Tfloat> operator/(const char *const expression) const {
      return CImg<Tfloat>(*this,false)/=expression;
    }

    //! Division operator.
    /**
       Similar to operator/=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
    **/
    template<typename t>
    CImg<_cimg_Tt> operator/(const CImg<t>& img) const {
      return (*this)*img.get_invert();
    }

    //! In-place modulo operator.
    /**
       Similar to operator+=(const t), except that it performs a modulo operation instead of an addition.
    **/
    template<typename t>
    CImg<T>& operator%=(const t value) {
      cimg_for(*this,ptrd,T) *ptrd = (T)cimg::mod(*ptrd,(T)value);
      return *this;
    }

    //! In-place modulo operator.
    /**
       Similar to operator+=(const char*), except that it performs a modulo operation instead of an addition.
    **/
    CImg<T>& operator%=(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"operator%=");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::mod(*ptrd,(T)mp.eval(x,y,z,c)); ++ptrd; }
      } catch (CImgException&) {
        cimg::exception_mode() = omode;
        *this%=CImg<T>(_width,_height,_depth,_spectrum,expression,true);
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    //! In-place modulo operator.
    /**
       Similar to operator+=(const CImg<t>&), except that it performs a modulo operation instead of an addition.
    **/
    template<typename t>
    CImg<T>& operator%=(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return *this%=+img;
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = cimg::mod(*ptrd,(T)*(ptrs++));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = cimg::mod(*ptrd,(T)*(ptrs++));
      }
      return *this;
    }

    //! Modulo operator.
    /**
       Similar to operator%=(const t), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
    **/
    template<typename t>
    CImg<_cimg_Tt> operator%(const t value) const {
      return CImg<_cimg_Tt>(*this,false)%=value;
    }

    //! Modulo operator.
    /**
       Similar to operator%=(const char*), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
    **/
    CImg<Tfloat> operator%(const char *const expression) const {
      return CImg<Tfloat>(*this,false)%=expression;
    }

    //! Modulo operator.
    /**
       Similar to operator%=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary.
    **/
    template<typename t>
    CImg<_cimg_Tt> operator%(const CImg<t>& img) const {
      return CImg<_cimg_Tt>(*this,false)%=img;
    }

    //! In-place bitwise AND operator.
    /**
       Similar to operator+=(const t), except that it performs a bitwise AND operation instead of an addition.
    **/
    template<typename t>
    CImg<T>& operator&=(const t value) {
      cimg_for(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd & (unsigned long)value);
      return *this;
    }

    //! In-place bitwise AND operator.
    /**
       Similar to operator+=(const char*), except that it performs a bitwise AND operation instead of an addition.
    **/
    CImg<T>& operator&=(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"operator&=");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd & (unsigned long)mp.eval(x,y,z,c)); ++ptrd; }
      } catch (CImgException&) {
        cimg::exception_mode() = omode;
        *this&=CImg<T>(_width,_height,_depth,_spectrum,expression,true);
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    //! In-place bitwise AND operator.
    /**
       Similar to operator+=(const CImg<t>&), except that it performs a bitwise AND operation instead of an addition.
    **/
    template<typename t>
    CImg<T>& operator&=(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return *this&=+img;
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)((unsigned long)*ptrd & (unsigned long)*(ptrs++));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((unsigned long)*ptrd & (unsigned long)*(ptrs++));
      }
      return *this;
    }

    //! Bitwise AND operator.
    /**
       Similar to operator&=(const t), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image is \c T.
    **/
    template<typename t>
    CImg<T> operator&(const t value) const {
      return (+*this)&=value;
    }

    //! Bitwise AND operator.
    /**
       Similar to operator&=(const char*), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image is \c T.
    **/
    CImg<T> operator&(const char *const expression) const {
      return (+*this)&=expression;
    }

    //! Bitwise AND operator.
    /**
       Similar to operator&=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image is \c T.
    **/
    template<typename t>
    CImg<T> operator&(const CImg<t>& img) const {
      return (+*this)&=img;
    }

    //! In-place bitwise OR operator.
    /**
       Similar to operator+=(const t), except that it performs a bitwise OR operation instead of an addition.
    **/
    template<typename t>
    CImg<T>& operator|=(const t value) {
      cimg_for(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd | (unsigned long)value);
      return *this;
    }

    //! In-place bitwise OR operator.
    /**
       Similar to operator+=(const char*), except that it performs a bitwise OR operation instead of an addition.
    **/
    CImg<T>& operator|=(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"operator|=");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd | (unsigned long)mp.eval(x,y,z,c)); ++ptrd; }
      } catch (CImgException&) {
        cimg::exception_mode() = omode;
        *this|=CImg<T>(_width,_height,_depth,_spectrum,expression,true);
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    //! In-place bitwise OR operator.
    /**
       Similar to operator+=(const CImg<t>&), except that it performs a bitwise OR operation instead of an addition.
    **/
    template<typename t>
    CImg<T>& operator|=(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return *this|=+img;
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)((unsigned long)*ptrd | (unsigned long)*(ptrs++));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((unsigned long)*ptrd | (unsigned long)*(ptrs++));
      }
      return *this;
    }

    //! Bitwise OR operator.
    /**
       Similar to operator|=(const t), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image is \c T.
    **/
    template<typename t>
    CImg<T> operator|(const t value) const {
      return (+*this)|=value;
    }

    //! Bitwise OR operator.
    /**
       Similar to operator|=(const char*), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image is \c T.
    **/
    CImg<T> operator|(const char *const expression) const {
      return (+*this)|=expression;
    }

    //! Bitwise OR operator.
    /**
       Similar to operator|=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image is \c T.
    **/
    template<typename t>
    CImg<T> operator|(const CImg<t>& img) const {
      return (+*this)|=img;
    }

    //! In-place bitwise XOR operator.
    /**
       Similar to operator+=(const t), except that it performs a bitwise XOR operation instead of an addition.
       \warning
       - It does \e not compute the \e power of pixel values. For this purpose, use pow(const t) instead.
    **/
    template<typename t>
    CImg<T>& operator^=(const t value) {
      cimg_for(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)value);
      return *this;
    }

    //! In-place bitwise XOR operator.
    /**
       Similar to operator+=(const char*), except that it performs a bitwise XOR operation instead of an addition.
       \warning
       - It does \e not compute the \e power of pixel values. For this purpose, use pow(const char*) instead.
    **/
    CImg<T>& operator^=(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"operator^=");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)mp.eval(x,y,z,c)); ++ptrd; }
      } catch (CImgException&) {
        cimg::exception_mode() = omode;
        *this^=CImg<T>(_width,_height,_depth,_spectrum,expression,true);
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    //! In-place bitwise XOR operator.
    /**
       Similar to operator+=(const CImg<t>&), except that it performs a bitwise XOR operation instead of an addition.
       \warning
       - It does \e not compute the \e power of pixel values. For this purpose, use pow(const CImg<t>&) instead.
    **/
    template<typename t>
    CImg<T>& operator^=(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return *this^=+img;
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)*(ptrs++));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)*(ptrs++));
      }
      return *this;
    }

    //! Bitwise XOR operator.
    /**
       Similar to operator^=(const t), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image is \c T.
    **/
    template<typename t>
    CImg<T> operator^(const t value) const {
      return (+*this)^=value;
    }

    //! Bitwise XOR operator.
    /**
       Similar to operator^=(const char*), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image is \c T.
    **/
    CImg<T> operator^(const char *const expression) const {
      return (+*this)^=expression;
    }

    //! Bitwise XOR operator.
    /**
       Similar to operator^=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image is \c T.
    **/
    template<typename t>
    CImg<T> operator^(const CImg<t>& img) const {
      return (+*this)^=img;
    }

    //! In-place bitwise left shift operator.
    /**
       Similar to operator+=(const t), except that it performs a bitwise left shift instead of an addition.
    **/
    template<typename t>
    CImg<T>& operator<<=(const t value) {
      cimg_for(*this,ptrd,T) *ptrd = (T)(((long)*ptrd) << (int)value);
      return *this;
    }

    //! In-place bitwise left shift operator.
    /**
       Similar to operator+=(const char*), except that it performs a bitwise left shift instead of an addition.
    **/
    CImg<T>& operator<<=(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"operator<<=");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd << (int)mp.eval(x,y,z,c)); ++ptrd; }
      } catch (CImgException&) {
        cimg::exception_mode() = omode;
        *this<<=CImg<T>(_width,_height,_depth,_spectrum,expression,true);
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    //! In-place bitwise left shift operator.
    /**
       Similar to operator+=(const CImg<t>&), except that it performs a bitwise left shift instead of an addition.
    **/
    template<typename t>
    CImg<T>& operator<<=(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return *this^=+img;
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)((long)*ptrd << (int)*(ptrs++));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((long)*ptrd << (int)*(ptrs++));
      }
      return *this;
    }

    //! Bitwise left shift operator.
    /**
       Similar to operator<<=(const t), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image is \c T.
    **/
    template<typename t>
    CImg<T> operator<<(const t value) const {
      return (+*this)<<=value;
    }

    //! Bitwise left shift operator.
    /**
       Similar to operator<<=(const char*), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image is \c T.
    **/
    CImg<T> operator<<(const char *const expression) const {
      return (+*this)<<=expression;
    }

    //! Bitwise left shift operator.
    /**
       Similar to operator<<=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image is \c T.
    **/
    template<typename t>
    CImg<T> operator<<(const CImg<t>& img) const {
      return (+*this)<<=img;
    }

    //! In-place bitwise right shift operator.
    /**
       Similar to operator+=(const t), except that it performs a bitwise right shift instead of an addition.
    **/
    template<typename t>
    CImg<T>& operator>>=(const t value) {
      cimg_for(*this,ptrd,T) *ptrd = (T)(((long)*ptrd) >> (int)value);
      return *this;
    }

    //! In-place bitwise right shift operator.
    /**
       Similar to operator+=(const char*), except that it performs a bitwise right shift instead of an addition.
    **/
    CImg<T>& operator>>=(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"operator<<=");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd >> (int)mp.eval(x,y,z,c)); ++ptrd; }
      } catch (CImgException&) {
        cimg::exception_mode() = omode;
        *this>>=CImg<T>(_width,_height,_depth,_spectrum,expression,true);
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    //! In-place bitwise right shift operator.
    /**
       Similar to operator+=(const CImg<t>&), except that it performs a bitwise right shift instead of an addition.
    **/
    template<typename t>
    CImg<T>& operator>>=(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return *this^=+img;
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)((long)*ptrd >> (int)*(ptrs++));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)((long)*ptrd >> (int)*(ptrs++));
      }
      return *this;
    }

    //! Bitwise right shift operator.
    /**
       Similar to operator>>=(const t), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image is \c T.
    **/
    template<typename t>
    CImg<T> operator>>(const t value) const {
      return (+*this)>>=value;
    }

    //! Bitwise right shift operator.
    /**
       Similar to operator>>=(const char*), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image is \c T.
    **/
    CImg<T> operator>>(const char *const expression) const {
      return (+*this)>>=expression;
    }

    //! Bitwise right shift operator.
    /**
       Similar to operator>>=(const CImg<t>&), except that it returns a new image instance instead of operating in-place.
       The pixel type of the returned image is \c T.
    **/
    template<typename t>
    CImg<T> operator>>(const CImg<t>& img) const {
      return (+*this)>>=img;
    }

    //! Bitwise inversion operator.
    /**
       Similar to operator-(), except that it compute the bitwise inverse instead of the opposite value.
    **/
    CImg<T> operator~() const {
      CImg<T> res(_width,_height,_depth,_spectrum);
      const T *ptrs = end();
      cimg_for(res,ptrd,T) { const unsigned long value = (unsigned long)*(--ptrs); *ptrd = (T)~value; }
      return res;
    }

    //! Test if two images have the same size and values.
    /**
       Return \c true if the image instance and the input image \c img have the same dimensions and pixel values, and \c false otherwise.
       \param img : input image to compare with.
       \note
       - The pixel buffer pointers data() of the two compared images do not have to be the same for operator==() to return \c true.
         Only the dimensions and the pixel values matter. Thus, the comparison can be \c true even for different pixel types \c T and \c t.
       \par Sample code :
       \code
       const CImg<float> img1(1,3,1,1, 0,1,2); // Construct a 1x3 vector [0;1;2] (with 'float' pixel values).
       const CImg<char> img2(1,3,1,1, 0,1,2);  // Construct a 1x3 vector [0;1;2] (with 'char' pixel values).
       if (img1==img2) {                       // Test succeeds, image dimensions and values are the same.
         std::printf("'img1' and 'img2' have same dimensions and values.");
       }
       \endcode
       \sa operator!=().
    **/
    template<typename t>
    bool operator==(const CImg<t>& img) const {
      const unsigned int siz = size();
      bool vequal = true;
      if (siz!=img.size()) return false;
      t *ptrs = img._data + siz;
      for (T *ptrd = _data + siz; vequal && ptrd>_data; vequal = vequal && ((*(--ptrd))==(*(--ptrs)))) {}
      return vequal;
    }

    //! Test if two images have different sizes or values.
    /**
       Return \c true if the image instance and the input image \c img have different dimensions or pixel values, and \c false otherwise.
       \param img : input image to compare with.
       \note
       - Writing \c img1!=img2 is equivalent to \c !(img1==img2).
       \sa operator==().
    **/
    template<typename t>
    bool operator!=(const CImg<t>& img) const {
      return !((*this)==img);
    }

    //! Construct an image list from two images.
    /**
       Return a new list of image (\c CImgList instance) containing exactly two elements :
         - A copy of the image instance, at position [\c 0].
         - A copy of the specified image \c img, at position [\c 1].

       \param img : Input image that will be the second image of the resulting list.
       \note
       - The family of operator,() is convenient to easily create list of images, but it is also \e quite \e slow in practice (see warning below).
       - Constructed lists contain no shared images. If image instance or input image \c img are shared, they are
         inserted as new non-shared copies in the resulting list.
       - The pixel type of the returned list may be a superset of the initial pixel type \c T, if necessary.
       \warning
       - Pipelining operator,() \c N times will perform \c N copies of the entire content of a (growing) image list.
         This may become very expensive in terms of speed and used memory. You should avoid using this technique to
         build a new CImgList instance from several images, if you are seeking for performance.
         Fast insertions of images in an image list are possible with CImgList<T>::insert(const CImg<t>&,unsigned int,bool) or
         move_to(CImgList<t>&,unsigned int).
       \par Sample code :
       \code
       const CImg<float>
          img1("reference.jpg"),
          img2 = img1.get_mirror('x'),
          img3 = img2.get_blur(5);
       const CImgList<float> list = (img1,img2); // Create list of two elements from 'img1' and 'img2'.
       (list,img3).display();                    // Display image list containing copies of 'img1','img2' and 'img3'.
       \endcode
       \image html ref_operator_comma.jpg
       \sa operator,(const CImgList<t>&) const,
           move_to(CImgList<t>&,unsigned int).
           CImgList<T>::insert(const CImg<t>&,unsigned int,bool).
    **/
    template<typename t>
    CImgList<_cimg_Tt> operator,(const CImg<t>& img) const {
      return CImgList<_cimg_Tt>(*this,img);
    }

    //! Construct an image list from image instance and an input image list.
    /**
       Return a new list of images (\c CImgList instance) containing exactly \c list.size() \c + \c 1 elements :
         - A copy of the image instance, at position [\c 0].
         - A copy of the specified image list \c list, from positions [\c 1] to [\c list.size()].

       \param list : Input image list that will be appended to the image instance.
       \note
       - Similar to operator,(const CImg<t>&) const, except that it takes an image list as an argument.
       \sa operator,(const CImg<t>&) const,
           CImgList<T>::insert(const CImgList<t>&,unsigned int,bool).
    **/
    template<typename t>
    CImgList<_cimg_Tt> operator,(const CImgList<t>& list) const {
      return CImgList<_cimg_Tt>(list,false).insert(*this,0);
    }

    //! Split image along specified axis.
    /**
       Return a new list of images (\c CImgList instance) containing the splitted components
       of the instance image along the specified axis.
       \param axis : Splitting axis (can be '\c x','\c y','\c z' or '\c c')
       \note
       - Similar to get_split(char,int) const, with default second argument.
       \par Sample code :
       \code
       const CImg<unsigned char> img("reference.jpg"); // Load a RGB color image.
       const CImgList<unsigned char> list = (img<'c'); // Get a list of its three R,G,B channels.
       (img,list).display();
       \endcode
       \image html ref_operator_less.jpg
       \sa get_split(char,int) const.
    **/
    CImgList<T> operator<(const char axis) const {
      return get_split(axis);
    }

    //@}
    //-------------------------------------
    //
    //! \name Instance Characteristics
    //@{
    //-------------------------------------

    //! Get the type of image pixel values as a C string.
    /**
       Return a \c char* string containing the usual type name of the image pixel values
       (i.e. a stringified version of the template parameter \c T).
       \note
       - The returned string may contain spaces (as in \c "unsigned char").
       - If the pixel type \c T does not correspond to a registered type, the string <tt>"unknown"</tt> is returned.
       \sa value_type.
    **/
    static const char* pixel_type() {
      return cimg::type<T>::string();
    }

    //! Get the number of image columns.
    /**
       Return the image width, i.e. the image dimension along the X-axis.
       \note
       - The width() of an empty image is equal to \c 0.
       - width() is typically equal to \c 1 when considering images as \e vectors for matrix calculations.
       - width() returns an \c int, although the image width is internally stored as an \c unsigned \c int.
         Using an \c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving
         \c unsigned \c int variables.
         Access to the initial \c unsigned \c int variable is possible (though not recommended) by <tt>(*this)._width</tt>.
       \sa height(),
           depth(),
           spectrum(),
           size().
    **/
    int width() const {
      return (int)_width;
    }

    //! Get the number of image rows.
    /**
       Return the image height, i.e. the image dimension along the Y-axis.
       \note
       - The height() of an empty image is equal to \c 0.
       - height() returns an \c int, although the image height is internally stored as an \c unsigned \c int.
         Using an \c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving
         \c unsigned \c int variables.
         Access to the initial \c unsigned \c int variable is possible (though not recommended) by <tt>(*this)._height</tt>.
       \sa width(),
           depth(),
           spectrum(),
           size().
    **/
    int height() const {
      return (int)_height;
    }

    //! Get the number of image slices.
    /**
       Return the image depth, i.e. the image dimension along the Z-axis.
       \note
       - The depth() of an empty image is equal to \c 0.
       - depth() is typically equal to \c 1 when considering usual 2d images. When depth()\c > \c 1, the image
         is said to be \e volumetric.
       - depth() returns an \c int, although the image depth is internally stored as an \c unsigned \c int.
         Using an \c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving
         \c unsigned \c int variables.
         Access to the initial \c unsigned \c int variable is possible (though not recommended) by <tt>(*this)._depth</tt>.
       \sa width(),
           height(),
           spectrum(),
           size().
    **/
    int depth() const {
      return (int)_depth;
    }

    //! Get the number of image channels.
    /**
       Return the number of image channels, i.e. the image dimension along the C-axis.
       \note
       - The spectrum() of an empty image is equal to \c 0.
       - spectrum() is typically equal to \c 1 when considering scalar-valued images, to \c 3 for RGB-coded color images, and to
         \c 4 for RGBA-coded color images (with alpha-channel). The number of channels of an image instance
         is not limited. The meaning of the pixel values is not linked up to the number of channels
         (e.g. a 4-channel image may indifferently stands for a RGBA or CMYK color image).
       - spectrum() returns an \c int, although the image spectrum is internally stored as an \c unsigned \c int.
         Using an \c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving
         \c unsigned \c int variables.
         Access to the initial \c unsigned \c int variable is possible (though not recommended) by <tt>(*this)._spectrum</tt>.
       \sa width(),
           height(),
           depth(),
           size().
    **/
    int spectrum() const {
      return (int)_spectrum;
    }

    //! Get the total number of pixel values.
    /**
       Return <tt>width()*\ref height()*\ref depth()*\ref spectrum()</tt>,
       i.e. the total number of values of type \c T in the pixel buffer of the image instance.
       \note
       - The size() of an empty image is equal to \c 0.
       - The allocated memory size for a pixel buffer of a non-shared \c CImg<T> instance is equal to <tt>size()*sizeof(T)</tt>.
       \par Sample code :
       \code
       const CImg<float> img(100,100,1,3);               // Construct new 100x100 color image.
       if (img.size()==30000)                            // Test succeeds.
         std::printf("Pixel buffer uses %lu bytes",
                     img.size()*sizeof(float));
       \endcode
       \sa width(),
           height(),
           depth(),
           spectrum().
    **/
    unsigned int size() const {
      return _width*_height*_depth*_spectrum;
    }

    //! Get a pointer to the first pixel value.
    /**
       Return a \c T*, or a \c const \c T* pointer to the first value in the pixel buffer of the image instance,
       whether the instance is \c const or not.
       \note
       - The data() of an empty image is equal to \c 0 (null pointer).
       - The allocated pixel buffer for the image instance starts from \c data()
         and goes to <tt>data()+\ref size()-1</tt> (included).
       - To get the pointer to one particular location of the pixel buffer, use data(unsigned int,unsigned int,unsigned int,unsigned int) instead.
       \sa operator T*() const,
           data(unsigned int,unsigned int,unsigned int,unsigned int).
    **/
    T* data() {
      return _data;
    }

    //! Get a pointer to the first pixel value \const.
    const T* data() const {
      return _data;
    }

    //! Get a pointer to a located pixel value.
    /**
       Return a \c T*, or a \c const \c T* pointer to the value located at (\c x,\c y,\c z,\c c) in the pixel buffer of the image instance,
       whether the instance is \c const or not.
       \param x : X-coordinate of the pixel value.
       \param y : Y-coordinate of the pixel value.
       \param z : Z-coordinate of the pixel value.
       \param c : C-coordinate of the pixel value.
       \note
       - Writing \c img.data(x,y,z,c) is equivalent to <tt>&(img(x,y,z,c))</tt>. Thus, this method has the same properties as
         operator()(unsigned int,unsigned int,unsigned int,unsigned int).
       \sa operator()(unsigned int,unsigned int,unsigned int,unsigned int),
           data().
     **/
#if cimg_verbosity>=3
    T *data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) {
      const unsigned int off = (unsigned int)offset(x,y,z,c);
      if (off>=size()) {
        cimg::warn(_cimg_instance
                   "data() : Invalid pointer request, at coordinates (%u,%u,%u,%u) [offset=%u].",
                   cimg_instance,
                   x,y,z,c,off);
        return _data;
      }
      return _data + off;
    }

    //! Get a pointer to a located pixel value \const.
    const T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const {
      return const_cast<CImg<T>*>(this)->data(x,y,z,c);
    }
#else
    T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) {
      return _data + x + y*_width + z*_width*_height + c*_width*_height*_depth;
    }

    const T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const {
      return _data + x + y*_width + z*_width*_height + c*_width*_height*_depth;
    }
#endif

    //! Get the offset to a located pixel value, with respect to the beginning of the pixel buffer.
    /**
       \param x : X-coordinate of the pixel value.
       \param y : Y-coordinate of the pixel value.
       \param z : Z-coordinate of the pixel value.
       \param c : C-coordinate of the pixel value.
       \note
       - Writing \c img.data(x,y,z,c) is equivalent to <tt>&(img(x,y,z,c)) - img.data()</tt>.
         Thus, this method has the same properties as operator()(unsigned int,unsigned int,unsigned int,unsigned int).
       \par Sample code :
       \code
       const CImg<float> img(100,100,1,3);      // Define a 100x100 RGB-color image.
       const long off = img.offset(10,10,0,2);  // Get the offset of the blue value of the pixel located at (10,10).
       const float val = img[off];              // Get the blue value of this pixel.
       \endcode
       \sa operator()(unsigned int,unsigned int,unsigned int,unsigned int),
           data(unsigned int,unsigned int,unsigned int,unsigned int).
    **/
    int offset(const int x, const int y=0, const int z=0, const int c=0) const {
      return x + y*_width + z*_width*_height + c*_width*_height*_depth;
    }

    //! Get a CImg<T>::iterator pointing to the first pixel value.
    /**
       \note
       - Equivalent to data().
       - It has been mainly defined for compatibility with STL naming conventions.
       \sa data().
     **/
    iterator begin() {
      return _data;
    }

    //! Get a CImg<T>::iterator pointing to the first value of the pixel buffer \const.
    const_iterator begin() const {
      return _data;
    }

    //! Get a CImg<T>::iterator pointing next to the last pixel value.
    /**
       \note
       - Writing \c img.end() is equivalent to <tt>img.data() + img.size()</tt>.
       - It has been mainly defined for compatibility with STL naming conventions.
       \warning
       - The returned iterator actually points to a value located \e outside the acceptable bounds of the pixel buffer. Trying
         to read or write the content of the returned iterator will probably result in a crash. Use it mainly as an
         strict upper bound for a CImg<T>::iterator.
       \par Sample code :
       \code
       CImg<float> img(100,100,1,3);                                     // Define a 100x100 RGB color image.
       for (CImg<float>::iterator it = img.begin(); it<img.end(); ++it)  // 'img.end()' used here as an upper bound for the iterator.
         *it = 0;
       \endcode
       \sa data().
    **/
    iterator end() {
      return _data + size();
    }

    //! Get a CImg<T>::iterator pointing next to the last pixel value \const.
    const_iterator end() const {
      return _data + size();
    }

    //! Get a reference to the first pixel value.
    /**
       \note
       - Writing \c img.front() is equivalent to <tt>img[0]</tt>, or <tt>img(0,0,0,0)</tt>.
       - It has been mainly defined for compatibility with STL naming conventions.
       \sa data(),
           offset(),
           begin().
    **/
    T& front() {
      return *_data;
    }

    //! Get a reference to the first pixel value \const.
    const T& front() const {
      return *_data;
    }

    //! Get a reference to the last pixel value.
    /**
       \note
       - Writing \c img.end() is equivalent to <tt>img[img.size()-1]</tt>, or
         <tt>img(img.width()-1,img.height()-1,img.depth()-1,img.spectrum()-1)</tt>.
       - It has been mainly defined for compatibility with STL naming conventions.
       \sa data(),
           offset(),
           end().
    **/
    T& back() {
      return *(_data + size() - 1);
    }

    //! Get a reference to the last pixel value \const.
    const T& back() const {
      return *(_data + size() - 1);
    }

    //! Access to a pixel value at a specified offset, using Dirichlet boundary conditions.
    /**
       Return a reference to the pixel value of the image instance located at a specified \c offset,
       or to a specified default value in case of out-of-bounds access.
       \param offset : Offset to the desired pixel value.
       \param out_value : Default value returned if \c offset is outside image bounds.
       \note
       - Writing \c img.at(offset,out_value) is similar to <tt>img[offset]</tt>, except that if \c offset
         is outside bounds (e.g. \c offset<0 or \c offset>=img.size()), a reference to a value \c out_value
         is safely returned instead.
       - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when
         you are \e not sure about the validity of the specified pixel offset.
       \sa operator()(),
           offset(),
           at(int).
    **/
    T& at(const int offset, const T out_value) {
      return (offset<0 || offset>=(int)size())?(cimg::temporary(out_value)=out_value):(*this)[offset];
    }

    //! Access to a pixel value at a specified offset, using Dirichlet boundary conditions \const.
    T at(const int offset, const T out_value) const {
      return (offset<0 || offset>=(int)size())?out_value:(*this)[offset];
    }

    //! Access to a pixel value at a specified offset, using Neumann boundary conditions.
    /**
       Return a reference to the pixel value of the image instance located at a specified \c offset,
       or to the nearest pixel location in the image instance in case of out-of-bounds access.
       \param offset : Offset to the desired pixel value.
       \note
       - Similar to at(int,const T), except that an out-of-bounds access returns the value of the
         nearest pixel in the image instance, regarding the specified offset, i.e.
         - If \c offset<0, then \c img[0] is returned.
         - If \c offset>=img.size(), then \c img[img.size()-1] is returned.
       - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when
         you are \e not sure about the validity of the specified pixel offset.
       - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _at(int).
       \sa operator()(),
           offset(),
           at(int,const T).
     **/
    T& at(const int offset) {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "at() : Empty instance.",
                                    cimg_instance);
      return _at(offset);
    }

    T& _at(const int offset) {
      const unsigned int siz = (unsigned int)size();
      return (*this)[offset<0?0:(unsigned int)offset>=siz?siz-1:offset];
    }

    //! Access to a pixel value at a specified offset, using Neumann boundary conditions \const.
    T at(const int offset) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "at() : Empty instance.",
                                    cimg_instance);
      return _at(offset);
    }

    T _at(const int offset) const {
      const unsigned int siz = (unsigned int)size();
      return (*this)[offset<0?0:(unsigned int)offset>=siz?siz-1:offset];
    }

    //! Access to a pixel value, using Dirichlet boundary conditions for the X-coordinate.
    /**
       Return a reference to the pixel value of the image instance located at (\c x,\c y,\c z,\c c),
       or to a specified default value in case of out-of-bounds access along the X-axis.
       \param x : X-coordinate of the pixel value.
       \param y : Y-coordinate of the pixel value.
       \param z : Z-coordinate of the pixel value.
       \param c : C-coordinate of the pixel value.
       \param out_value : Default value returned if \c (\c x,\c y,\c z,\c c) is outside image bounds.
       \note
       - Similar to operator()(), except that an out-of-bounds access along the X-axis returns the specified value \c out_value.
       - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when
         you are \e not sure about the validity of the specified pixel coordinates.
       \warning
       - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds.
       \sa operator()(),
           at(int,const T).
           atX(int,int,int,int),
           atXY(int,int,int,int,const T),
           atXYZ(int,int,int,int,const T),
           atXYZC(int,int,int,int,const T).
    **/
    T& atX(const int x, const int y, const int z, const int c, const T out_value) {
      return (x<0 || x>=width())?(cimg::temporary(out_value)=out_value):(*this)(x,y,z,c);
    }

    //! Access to a pixel value, using Dirichlet boundary conditions for the X-coordinate \const.
    T atX(const int x, const int y, const int z, const int c, const T out_value) const {
      return (x<0 || x>=width())?out_value:(*this)(x,y,z,c);
    }

    //! Access to a pixel value, using Neumann boundary conditions for the X-coordinate.
    /**
       Return a reference to the pixel value of the image instance located at (\c x,\c y,\c z,\c c),
       or to the nearest pixel location in the image instance in case of out-of-bounds access along the X-axis.
       \param x : X-coordinate of the pixel value.
       \param y : Y-coordinate of the pixel value.
       \param z : Z-coordinate of the pixel value.
       \param c : C-coordinate of the pixel value.
       \note
       - Similar to at(int,int,int,int,const T), except that an out-of-bounds access returns the value of the
         nearest pixel in the image instance, regarding the specified X-coordinate.
       - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when
         you are \e not sure about the validity of the specified pixel coordinates.
       - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _at(int,int,int,int).
       \warning
       - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds.
       \sa operator()(),
           at(int),
           atX(int,int,int,int,const T),
           atXY(int,int,int,int),
           atXYZ(int,int,int,int),
           atXYZC(int,int,int,int).
     **/
    T& atX(const int x, const int y=0, const int z=0, const int c=0) {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "atX() : Empty instance.",
                                    cimg_instance);
      return _atX(x,y,z,c);
    }

    T& _atX(const int x, const int y=0, const int z=0, const int c=0) {
      return (*this)(x<0?0:(x>=width()?width()-1:x),y,z,c);
    }

    //! Access to a pixel value, using Neumann boundary conditions for the X-coordinate \const.
    T atX(const int x, const int y=0, const int z=0, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "atX() : Empty instance.",
                                    cimg_instance);
      return _atX(x,y,z,c);
    }

    T _atX(const int x, const int y=0, const int z=0, const int c=0) const {
      return (*this)(x<0?0:(x>=width()?width()-1:x),y,z,c);
    }

    //! Access to a pixel value, using Dirichlet boundary conditions for the X and Y-coordinates.
    /**
       Similar to atX(int,int,int,int,const T), except that boundary checking is performed both on X and Y-coordinates.
    **/
    T& atXY(const int x, const int y, const int z, const int c, const T out_value) {
      return (x<0 || y<0 || x>=width() || y>=height())?(cimg::temporary(out_value)=out_value):(*this)(x,y,z,c);
    }

    //! Access to a pixel value, using Dirichlet boundary conditions for the X and Y coordinates \const.
    T atXY(const int x, const int y, const int z, const int c, const T out_value) const {
      return (x<0 || y<0 || x>=width() || y>=height())?out_value:(*this)(x,y,z,c);
    }

    //! Access to a pixel value, using Neumann boundary conditions for the X and Y-coordinates.
    /**
       Similar to atX(int,int,int,int), except that boundary checking is performed both on X and Y-coordinates.
       \note
       - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _atXY(int,int,int,int).
     **/
    T& atXY(const int x, const int y, const int z=0, const int c=0) {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "atXY() : Empty instance.",
                                    cimg_instance);
      return _atXY(x,y,z,c);
    }

    T& _atXY(const int x, const int y, const int z=0, const int c=0) {
      return (*this)(x<0?0:(x>=width()?width()-1:x), y<0?0:(y>=height()?height()-1:y),z,c);
    }

    //! Access to a pixel value, using Neumann boundary conditions for the X and Y-coordinates \const.
    T atXY(const int x, const int y, const int z=0, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "atXY() : Empty instance.",
                                    cimg_instance);
      return _atXY(x,y,z,c);
    }

    T _atXY(const int x, const int y, const int z=0, const int c=0) const {
      return (*this)(x<0?0:(x>=width()?width()-1:x), y<0?0:(y>=height()?height()-1:y),z,c);
    }

    //! Access to a pixel value, using Dirichlet boundary conditions for the X,Y and Z-coordinates.
    /**
       Similar to atX(int,int,int,int,const T), except that boundary checking is performed both on X,Y and Z-coordinates.
    **/
    T& atXYZ(const int x, const int y, const int z, const int c, const T out_value) {
      return (x<0 || y<0 || z<0 || x>=width() || y>=height() || z>=depth())?
        (cimg::temporary(out_value)=out_value):(*this)(x,y,z,c);
    }

    //! Access to a pixel value, using Dirichlet boundary conditions for the X,Y and Z-coordinates \const.
    T atXYZ(const int x, const int y, const int z, const int c, const T out_value) const {
      return (x<0 || y<0 || z<0 || x>=width() || y>=height() || z>=depth())?out_value:(*this)(x,y,z,c);
    }

    //! Access to a pixel value, using Neumann boundary conditions for the X,Y and Z-coordinates.
    /**
       Similar to atX(int,int,int,int), except that boundary checking is performed both on X,Y and Z-coordinates.
       \note
       - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _atXYZ(int,int,int,int).
    **/
    T& atXYZ(const int x, const int y, const int z, const int c=0) {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "atXYZ() : Empty instance.",
                                    cimg_instance);
      return _atXYZ(x,y,z,c);
    }

    T& _atXYZ(const int x, const int y, const int z, const int c=0) {
      return (*this)(x<0?0:(x>=width()?width()-1:x),y<0?0:(y>=height()?height()-1:y),
                     z<0?0:(z>=depth()?depth()-1:z),c);
    }

    //! Access to a pixel value, using Neumann boundary conditions for the X,Y and Z-coordinates \const.
    T atXYZ(const int x, const int y, const int z, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "atXYZ() : Empty instance.",
                                    cimg_instance);
      return _atXYZ(x,y,z,c);
    }

    T _atXYZ(const int x, const int y, const int z, const int c=0) const {
      return (*this)(x<0?0:(x>=width()?width()-1:x),y<0?0:(y>=height()?height()-1:y),
                     z<0?0:(z>=depth()?depth()-1:z),c);
    }

    //! Access to a pixel value, using Dirichlet boundary conditions.
    /**
       Similar to atX(int,int,int,int,const T), except that boundary checking is performed on all X,Y,Z and C-coordinates.
    **/
    T& atXYZC(const int x, const int y, const int z, const int c, const T out_value) {
      return (x<0 || y<0 || z<0 || c<0 || x>=width() || y>=height() || z>=depth() || c>=spectrum())?
        (cimg::temporary(out_value)=out_value):(*this)(x,y,z,c);
    }

    //! Access to a pixel value, using Dirichlet boundary conditions \const.
    T atXYZC(const int x, const int y, const int z, const int c, const T out_value) const {
      return (x<0 || y<0 || z<0 || c<0 || x>=width() || y>=height() || z>=depth() || c>=spectrum())?out_value:(*this)(x,y,z,c);
    }

    //! Access to a pixel value, using Neumann boundary conditions.
    /**
       Similar to atX(int,int,int,int), except that boundary checking is performed on all X,Y,Z and C-coordinates.
       \note
       - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _atXYZC(int,int,int,int).
    **/
    T& atXYZC(const int x, const int y, const int z, const int c) {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "atXYZC() : Empty instance.",
                                    cimg_instance);
      return _atXYZC(x,y,z,c);
    }

    T& _atXYZC(const int x, const int y, const int z, const int c) {
      return (*this)(x<0?0:(x>=width()?width()-1:x), y<0?0:(y>=height()?height()-1:y),
                     z<0?0:(z>=depth()?depth()-1:z), c<0?0:(c>=spectrum()?spectrum()-1:c));
    }

    //! Access to a pixel value, using Neumann boundary conditions \const.
    T atXYZC(const int x, const int y, const int z, const int c) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "atXYZC() : Empty instance.",
                                    cimg_instance);
      return _atXYZC(x,y,z,c);
    }

    T _atXYZC(const int x, const int y, const int z, const int c) const {
      return (*this)(x<0?0:(x>=width()?width()-1:x), y<0?0:(y>=height()?height()-1:y),
                     z<0?0:(z>=depth()?depth()-1:z), c<0?0:(c>=spectrum()?spectrum()-1:c));
    }

    //! Get pixel value, using linear interpolation and Dirichlet boundary conditions for the X-coordinate.
    /**
       Return a linearly-interpolated pixel value of the image instance located at (\c fx,\c y,\c z,\c c),
       or a specified default value in case of out-of-bounds access along the X-axis.
       \param fx : X-coordinate of the pixel value (float-valued).
       \param y : Y-coordinate of the pixel value.
       \param z : Z-coordinate of the pixel value.
       \param c : C-coordinate of the pixel value.
       \param out_value : Default value returned if \c (\c fx,\c y,\c z,\c c) is outside image bounds.
       \note
       - Similar to atX(int,int,int,int,const T), except that the returned pixel value is approximated by a linear interpolation along the X-axis,
         if corresponding coordinates are not integers.
       - The type of the returned pixel value is extended to \c float, if the pixel type \c T is not float-valued.
       \warning
       - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds.
       \sa operator()(),
           atX(int,int,int,int,const T),
           linear_atX(float,int,int,int) const,
           linear_atXY(float,float,int,int,const T) const,
           linear_atXYZ(float,float,float,int,const T) const,
           linear_atXYZC(float,float,float,float,const T) const.
    **/
    Tfloat linear_atX(const float fx, const int y, const int z, const int c, const T out_value) const {
      const int
        x = (int)fx - (fx>=0?0:1), nx = x + 1;
      const float
        dx = fx - x;
      const Tfloat
        Ic = (Tfloat)atX(x,y,z,c,out_value), In = (Tfloat)atXY(nx,y,z,c,out_value);
      return Ic + dx*(In-Ic);
    }

    //! Get pixel value, using linear interpolation and Neumann boundary conditions for the X-coordinate.
    /**
       Return a linearly-interpolated pixel value of the image instance located at (\c fx,\c y,\c z,\c c),
       or the value of the nearest pixel location in the image instance in case of out-of-bounds access along the X-axis.
       \param fx : X-coordinate of the pixel value (float-valued).
       \param y : Y-coordinate of the pixel value.
       \param z : Z-coordinate of the pixel value.
       \param c : C-coordinate of the pixel value.
       \note
       - Similar to linear_atX(float,int,int,int,const T) const, except that an out-of-bounds access returns the value of the
         nearest pixel in the image instance, regarding the specified X-coordinate.
       - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _linear_atX(float,int,int,int).
       \warning
       - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds.
       \sa operator()(),
           atX(int,int,int,int),
           linear_atX(float,int,int,int,const T) const,
           linear_atXY(float,float,int,int) const,
           linear_atXYZ(float,float,float,int) const,
           linear_atXYZC(float,float,float,float) const.
    **/
    Tfloat linear_atX(const float fx, const int y=0, const int z=0, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "linear_atX() : Empty instance.",
                                    cimg_instance);

      return _linear_atX(fx,y,z,c);
    }

    Tfloat _linear_atX(const float fx, const int y=0, const int z=0, const int c=0) const {
      const float
        nfx = fx<0?0:(fx>_width-1?_width-1:fx);
      const unsigned int
        x = (unsigned int)nfx;
      const float
        dx = nfx - x;
      const unsigned int
        nx = dx>0?x+1:x;
      const Tfloat
        Ic = (Tfloat)(*this)(x,y,z,c), In = (Tfloat)(*this)(nx,y,z,c);
      return Ic + dx*(In-Ic);
    }

    //! Get pixel value, using linear interpolation and Dirichlet boundary conditions for the X and Y-coordinates.
    /**
       Similar to linear_atX(float,int,int,int,const T) const, except that the linear interpolation and the boundary checking
       are achieved both for X and Y-coordinates.
    **/
    Tfloat linear_atXY(const float fx, const float fy, const int z, const int c, const T out_value) const {
      const int
        x = (int)fx - (fx>=0?0:1), nx = x + 1,
        y = (int)fy - (fy>=0?0:1), ny = y + 1;
      const float
        dx = fx - x,
        dy = fy - y;
      const Tfloat
        Icc = (Tfloat)atXY(x,y,z,c,out_value),  Inc = (Tfloat)atXY(nx,y,z,c,out_value),
        Icn = (Tfloat)atXY(x,ny,z,c,out_value), Inn = (Tfloat)atXY(nx,ny,z,c,out_value);
      return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
    }

    //! Get pixel value, using linear interpolation and Neumann boundary conditions for the X and Y-coordinates.
    /**
       Similar to linear_atX(float,int,int,int) const, except that the linear interpolation and the boundary checking
       are achieved both for X and Y-coordinates.
       \note
       - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _linear_atXY(float,float,int,int).
    **/
    Tfloat linear_atXY(const float fx, const float fy, const int z=0, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "linear_atXY() : Empty instance.",
                                    cimg_instance);

      return _linear_atXY(fx,fy,z,c);
    }

    Tfloat _linear_atXY(const float fx, const float fy, const int z=0, const int c=0) const {
      const float
        nfx = fx<0?0:(fx>_width-1?_width-1:fx),
        nfy = fy<0?0:(fy>_height-1?_height-1:fy);
      const unsigned int
        x = (unsigned int)nfx,
        y = (unsigned int)nfy;
      const float
        dx = nfx - x,
        dy = nfy - y;
      const unsigned int
        nx = dx>0?x+1:x,
        ny = dy>0?y+1:y;
      const Tfloat
        Icc = (Tfloat)(*this)(x,y,z,c),  Inc = (Tfloat)(*this)(nx,y,z,c),
        Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c);
      return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
    }

    //! Get pixel value, using linear interpolation and Dirichlet boundary conditions for the X,Y and Z-coordinates.
    /**
       Similar to linear_atX(float,int,int,int,const T) const, except that the linear interpolation and the boundary checking
       are achieved both for X,Y and Z-coordinates.
    **/
    Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int c, const T out_value) const {
      const int
        x = (int)fx - (fx>=0?0:1), nx = x + 1,
        y = (int)fy - (fy>=0?0:1), ny = y + 1,
        z = (int)fz - (fz>=0?0:1), nz = z + 1;
      const float
        dx = fx - x,
        dy = fy - y,
        dz = fz - z;
      const Tfloat
        Iccc = (Tfloat)atXYZ(x,y,z,c,out_value), Incc = (Tfloat)atXYZ(nx,y,z,c,out_value),
        Icnc = (Tfloat)atXYZ(x,ny,z,c,out_value), Innc = (Tfloat)atXYZ(nx,ny,z,c,out_value),
        Iccn = (Tfloat)atXYZ(x,y,nz,c,out_value), Incn = (Tfloat)atXYZ(nx,y,nz,c,out_value),
        Icnn = (Tfloat)atXYZ(x,ny,nz,c,out_value), Innn = (Tfloat)atXYZ(nx,ny,nz,c,out_value);
      return Iccc +
        dx*(Incc-Iccc +
            dy*(Iccc+Innc-Icnc-Incc +
                dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
            dz*(Iccc+Incn-Iccn-Incc)) +
        dy*(Icnc-Iccc +
            dz*(Iccc+Icnn-Iccn-Icnc)) +
        dz*(Iccn-Iccc);
    }

    //! Get pixel value, using linear interpolation and Neumann boundary conditions for the X,Y and Z-coordinates.
    /**
       Similar to linear_atX(float,int,int,int) const, except that the linear interpolation and the boundary checking
       are achieved both for X,Y and Z-coordinates.
       \note
       - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _linear_atXYZ(float,float,float,int).
    **/
    Tfloat linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "linear_atXYZ() : Empty instance.",
                                    cimg_instance);

      return _linear_atXYZ(fx,fy,fz,c);
    }

    Tfloat _linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int c=0) const {
      const float
        nfx = fx<0?0:(fx>_width-1?_width-1:fx),
        nfy = fy<0?0:(fy>_height-1?_height-1:fy),
        nfz = fz<0?0:(fz>_depth-1?_depth-1:fz);
      const unsigned int
        x = (unsigned int)nfx,
        y = (unsigned int)nfy,
        z = (unsigned int)nfz;
      const float
        dx = nfx - x,
        dy = nfy - y,
        dz = nfz - z;
      const unsigned int
        nx = dx>0?x+1:x,
        ny = dy>0?y+1:y,
        nz = dz>0?z+1:z;
      const Tfloat
        Iccc = (Tfloat)(*this)(x,y,z,c), Incc = (Tfloat)(*this)(nx,y,z,c),
        Icnc = (Tfloat)(*this)(x,ny,z,c), Innc = (Tfloat)(*this)(nx,ny,z,c),
        Iccn = (Tfloat)(*this)(x,y,nz,c), Incn = (Tfloat)(*this)(nx,y,nz,c),
        Icnn = (Tfloat)(*this)(x,ny,nz,c), Innn = (Tfloat)(*this)(nx,ny,nz,c);
      return Iccc +
        dx*(Incc-Iccc +
            dy*(Iccc+Innc-Icnc-Incc +
                dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
            dz*(Iccc+Incn-Iccn-Incc)) +
        dy*(Icnc-Iccc +
            dz*(Iccc+Icnn-Iccn-Icnc)) +
        dz*(Iccn-Iccc);
    }

    //! Get pixel value, using linear interpolation and Dirichlet boundary conditions for all X,Y,Z and C-coordinates.
    /**
       Similar to linear_atX(float,int,int,int,const T) const, except that the linear interpolation and the boundary checking
       are achieved for all X,Y,Z and C-coordinates.
    **/
    Tfloat linear_atXYZC(const float fx, const float fy, const float fz, const float fc, const T out_value) const {
      const int
        x = (int)fx - (fx>=0?0:1), nx = x + 1,
        y = (int)fy - (fy>=0?0:1), ny = y + 1,
        z = (int)fz - (fz>=0?0:1), nz = z + 1,
        c = (int)fc - (fc>=0?0:1), nc = c + 1;
      const float
        dx = fx - x,
        dy = fy - y,
        dz = fz - z,
        dc = fc - c;
      const Tfloat
        Icccc = (Tfloat)atXYZC(x,y,z,c,out_value), Inccc = (Tfloat)atXYZC(nx,y,z,c,out_value),
        Icncc = (Tfloat)atXYZC(x,ny,z,c,out_value), Inncc = (Tfloat)atXYZC(nx,ny,z,c,out_value),
        Iccnc = (Tfloat)atXYZC(x,y,nz,c,out_value), Incnc = (Tfloat)atXYZC(nx,y,nz,c,out_value),
        Icnnc = (Tfloat)atXYZC(x,ny,nz,c,out_value), Innnc = (Tfloat)atXYZC(nx,ny,nz,c,out_value),
        Icccn = (Tfloat)atXYZC(x,y,z,nc,out_value), Inccn = (Tfloat)atXYZC(nx,y,z,nc,out_value),
        Icncn = (Tfloat)atXYZC(x,ny,z,nc,out_value), Inncn = (Tfloat)atXYZC(nx,ny,z,nc,out_value),
        Iccnn = (Tfloat)atXYZC(x,y,nz,nc,out_value), Incnn = (Tfloat)atXYZC(nx,y,nz,nc,out_value),
        Icnnn = (Tfloat)atXYZC(x,ny,nz,nc,out_value), Innnn = (Tfloat)atXYZC(nx,ny,nz,nc,out_value);
      return Icccc +
        dx*(Inccc-Icccc +
            dy*(Icccc+Inncc-Icncc-Inccc +
                dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
                    dc*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
                dc*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
            dz*(Icccc+Incnc-Iccnc-Inccc +
                dc*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
            dc*(Icccc+Inccn-Inccc-Icccn)) +
        dy*(Icncc-Icccc +
            dz*(Icccc+Icnnc-Iccnc-Icncc +
                dc*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
            dc*(Icccc+Icncn-Icncc-Icccn)) +
        dz*(Iccnc-Icccc +
            dc*(Icccc+Iccnn-Iccnc-Icccn)) +
        dc*(Icccn-Icccc);
    }

    //! Get pixel value, using linear interpolation and Neumann boundary conditions for all X,Y,Z and C-coordinates.
    /**
       Similar to linear_atX(float,int,int,int) const, except that the linear interpolation and the boundary checking
       are achieved for all X,Y,Z and C-coordinates.
       \note
       - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _linear_atXYZC(float,float,float,float).
    **/
    Tfloat linear_atXYZC(const float fx, const float fy=0, const float fz=0, const float fc=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "linear_atXYZC() : Empty instance.",
                                    cimg_instance);

      return _linear_atXYZC(fx,fy,fz,fc);
    }

    Tfloat _linear_atXYZC(const float fx, const float fy=0, const float fz=0, const float fc=0) const {
      const float
        nfx = fx<0?0:(fx>_width-1?_width-1:fx),
        nfy = fy<0?0:(fy>_height-1?_height-1:fy),
        nfz = fz<0?0:(fz>_depth-1?_depth-1:fz),
        nfc = fc<0?0:(fc>_spectrum-1?_spectrum-1:fc);
      const unsigned int
        x = (unsigned int)nfx,
        y = (unsigned int)nfy,
        z = (unsigned int)nfz,
        c = (unsigned int)nfc;
      const float
        dx = nfx - x,
        dy = nfy - y,
        dz = nfz - z,
        dc = nfc - c;
      const unsigned int
        nx = dx>0?x+1:x,
        ny = dy>0?y+1:y,
        nz = dz>0?z+1:z,
        nc = dc>0?c+1:c;
      const Tfloat
        Icccc = (Tfloat)(*this)(x,y,z,c), Inccc = (Tfloat)(*this)(nx,y,z,c),
        Icncc = (Tfloat)(*this)(x,ny,z,c), Inncc = (Tfloat)(*this)(nx,ny,z,c),
        Iccnc = (Tfloat)(*this)(x,y,nz,c), Incnc = (Tfloat)(*this)(nx,y,nz,c),
        Icnnc = (Tfloat)(*this)(x,ny,nz,c), Innnc = (Tfloat)(*this)(nx,ny,nz,c),
        Icccn = (Tfloat)(*this)(x,y,z,nc), Inccn = (Tfloat)(*this)(nx,y,z,nc),
        Icncn = (Tfloat)(*this)(x,ny,z,nc), Inncn = (Tfloat)(*this)(nx,ny,z,nc),
        Iccnn = (Tfloat)(*this)(x,y,nz,nc), Incnn = (Tfloat)(*this)(nx,y,nz,nc),
        Icnnn = (Tfloat)(*this)(x,ny,nz,nc), Innnn = (Tfloat)(*this)(nx,ny,nz,nc);
      return Icccc +
        dx*(Inccc-Icccc +
            dy*(Icccc+Inncc-Icncc-Inccc +
                dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
                    dc*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
                dc*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
            dz*(Icccc+Incnc-Iccnc-Inccc +
                dc*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
            dc*(Icccc+Inccn-Inccc-Icccn)) +
        dy*(Icncc-Icccc +
            dz*(Icccc+Icnnc-Iccnc-Icncc +
                dc*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
            dc*(Icccc+Icncn-Icncc-Icccn)) +
        dz*(Iccnc-Icccc +
            dc*(Icccc+Iccnn-Iccnc-Icccn)) +
        dc*(Icccn-Icccc);
    }

    //! Get pixel value, using cubic interpolation and Dirichlet boundary conditions for the X-coordinate.
    /**
       Return a cubicly-interpolated pixel value of the image instance located at (\c fx,\c y,\c z,\c c),
       or a specified default value in case of out-of-bounds access along the X-axis.
       \param fx : X-coordinate of the pixel value (float-valued).
       \param y : Y-coordinate of the pixel value.
       \param z : Z-coordinate of the pixel value.
       \param c : C-coordinate of the pixel value.
       \param out_value : Default value returned if \c (\c fx,\c y,\c z,\c c) is outside image bounds.
       \note
       - Similar to linear_atX(float,int,int,int,const T) const, except that the returned pixel value is approximated by a
         \e cubic interpolation along the X-axis.
       - The type of the returned pixel value is extended to \c float, if the pixel type \c T is not float-valued.
       \warning
       - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds.
       \sa operator()(),
           atX(int,int,int,int,const T),
           linear_atX(float,int,int,int,const T) const,
           cubic_atX(float,int,int,int) const,
           cubic_atXY(float,float,int,int,const T) const,
           cubic_atXYZ(float,float,float,int,const T) const.
    **/
    Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const T out_value) const {
      const int
        x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2;
      const float
        dx = fx - x;
      const Tfloat
        Ip = (Tfloat)atX(px,y,z,c,out_value), Ic = (Tfloat)atX(x,y,z,c,out_value),
        In = (Tfloat)atX(nx,y,z,c,out_value), Ia = (Tfloat)atX(ax,y,z,c,out_value);
      return Ic + 0.5f*(dx*(-Ip+In) + dx*dx*(2*Ip-5*Ic+4*In-Ia) + dx*dx*dx*(-Ip+3*Ic-3*In+Ia));
    }

    //! Get damped pixel value, using cubic interpolation and Dirichlet boundary conditions for the X-coordinate.
    /**
       Similar to cubic_atX(float,int,int,int,const T) const, except that you can specify the authorized minimum and maximum of the returned value.
    **/
    Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const T out_value,
                     const Tfloat min_value, const Tfloat max_value) const {
      const Tfloat val = cubic_atX(fx,y,z,c,out_value);
      return val<min_value?min_value:val>max_value?max_value:val;
    }

    //! Get pixel value, using cubic interpolation and Neumann boundary conditions for the X-coordinate.
    /**
       Return a cubicly-interpolated pixel value of the image instance located at (\c fx,\c y,\c z,\c c),
       or the value of the nearest pixel location in the image instance in case of out-of-bounds access along the X-axis.
       \param fx : X-coordinate of the pixel value (float-valued).
       \param y : Y-coordinate of the pixel value.
       \param z : Z-coordinate of the pixel value.
       \param c : C-coordinate of the pixel value.
       \note
       - Similar to cubic_atX(float,int,int,int,const T) const, except that the returned pixel value is approximated by a cubic interpolation along the X-axis.
       - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _cubic_atX(float,int,int,int).
       \warning
       - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds.
       \sa operator()(),
           atX(int,int,int,int),
           linear_atX(float,int,int,int) const,
           cubic_atX(float,int,int,int,const T) const,
           cubic_atXY(float,float,int,int) const,
           cubic_atXYZ(float,float,float,int) const.
    **/
    Tfloat cubic_atX(const float fx, const int y=0, const int z=0, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "cubic_atX() : Empty instance.",
                                    cimg_instance);
      return _cubic_atX(fx,y,z,c);
    }

    Tfloat _cubic_atX(const float fx, const int y=0, const int z=0, const int c=0) const {
      const float
        nfx = fx<0?0:(fx>_width-1?_width-1:fx);
      const int
        x = (int)nfx;
      const float
        dx = nfx - x;
      const int
        px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=width()?width()-1:x+2;
      const Tfloat
        Ip = (Tfloat)(*this)(px,y,z,c), Ic = (Tfloat)(*this)(x,y,z,c),
        In = (Tfloat)(*this)(nx,y,z,c), Ia = (Tfloat)(*this)(ax,y,z,c);
      return Ic + 0.5f*(dx*(-Ip+In) + dx*dx*(2*Ip-5*Ic+4*In-Ia) + dx*dx*dx*(-Ip+3*Ic-3*In+Ia));
    }

    //! Get damped pixel value, using cubic interpolation and Neumann boundary conditions for the X-coordinate.
    /**
       Similar to cubic_atX(float,int,int,int) const, except that you can specify the authorized minimum and maximum of the returned value.
    **/
    Tfloat cubic_atX(const float fx, const int y, const int z, const int c,
                     const Tfloat min_value, const Tfloat max_value) const {
      const Tfloat val = cubic_atX(fx,y,z,c);
      return val<min_value?min_value:val>max_value?max_value:val;
    }

    Tfloat _cubic_atX(const float fx, const int y, const int z, const int c,
                      const Tfloat min_value, const Tfloat max_value) const {
      const Tfloat val = _cubic_atX(fx,y,z,c);
      return val<min_value?min_value:val>max_value?max_value:val;
    }

    //! Get pixel value, using cubic interpolation and Dirichlet boundary conditions for the X and Y-coordinates.
    /**
       Similar to cubic_atX(float,int,int,int,const T) const, except that the cubic interpolation and boundary checking
       are achieved both for X and Y-coordinates.
    **/
    Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, const T out_value) const {
      const int
        x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2,
        y = (int)fy - (fy>=0?0:1), py = y - 1, ny = y + 1, ay = y + 2;
      const float dx = fx - x, dy = fy - y;
      const Tfloat
        Ipp = (Tfloat)atXY(px,py,z,c,out_value), Icp = (Tfloat)atXY(x,py,z,c,out_value), Inp = (Tfloat)atXY(nx,py,z,c,out_value), Iap = (Tfloat)atXY(ax,py,z,c,out_value),
        Ip = Icp + 0.5f*(dx*(-Ipp+Inp) + dx*dx*(2*Ipp-5*Icp+4*Inp-Iap) + dx*dx*dx*(-Ipp+3*Icp-3*Inp+Iap)),
        Ipc = (Tfloat)atXY(px,y,z,c,out_value),  Icc = (Tfloat)atXY(x, y,z,c,out_value), Inc = (Tfloat)atXY(nx,y,z,c,out_value),  Iac = (Tfloat)atXY(ax,y,z,c,out_value),
        Ic = Icc + 0.5f*(dx*(-Ipc+Inc) + dx*dx*(2*Ipc-5*Icc+4*Inc-Iac) + dx*dx*dx*(-Ipc+3*Icc-3*Inc+Iac)),
        Ipn = (Tfloat)atXY(px,ny,z,c,out_value), Icn = (Tfloat)atXY(x,ny,z,c,out_value), Inn = (Tfloat)atXY(nx,ny,z,c,out_value), Ian = (Tfloat)atXY(ax,ny,z,c,out_value),
        In = Icn + 0.5f*(dx*(-Ipn+Inn) + dx*dx*(2*Ipn-5*Icn+4*Inn-Ian) + dx*dx*dx*(-Ipn+3*Icn-3*Inn+Ian)),
        Ipa = (Tfloat)atXY(px,ay,z,c,out_value), Ica = (Tfloat)atXY(x,ay,z,c,out_value), Ina = (Tfloat)atXY(nx,ay,z,c,out_value), Iaa = (Tfloat)atXY(ax,ay,z,c,out_value),
        Ia = Ica + 0.5f*(dx*(-Ipa+Ina) + dx*dx*(2*Ipa-5*Ica+4*Ina-Iaa) + dx*dx*dx*(-Ipa+3*Ica-3*Ina+Iaa));
      return Ic + 0.5f*(dy*(-Ip+In) + dy*dy*(2*Ip-5*Ic+4*In-Ia) + dy*dy*dy*(-Ip+3*Ic-3*In+Ia));
    }

    //! Get damped pixel value, using cubic interpolation and Dirichlet boundary conditions for the X and Y-coordinates.
    /**
       Similar to cubic_atXY(float,float,int,int,const T) const, except that you can specify the authorized minimum and maximum of the returned value.
    **/
    Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, const T out_value,
                      const Tfloat min_value, const Tfloat max_value) const {
      const Tfloat val = cubic_atXY(fx,fy,z,c,out_value);
      return val<min_value?min_value:val>max_value?max_value:val;
    }

    //! Get pixel value, using cubic interpolation and Neumann boundary conditions for the X and Y-coordinates.
    /**
       Similar to cubic_atX(float,int,int,int) const, except that the cubic interpolation and boundary checking
       are achieved for both X and Y-coordinates.
       \note
       - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _cubic_atXY(float,float,int,int).
    **/
    Tfloat cubic_atXY(const float fx, const float fy, const int z=0, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "cubic_atXY() : Empty instance.",
                                    cimg_instance);
      return _cubic_atXY(fx,fy,z,c);
    }

    Tfloat _cubic_atXY(const float fx, const float fy, const int z=0, const int c=0) const {
      const float
        nfx = fx<0?0:(fx>_width-1?_width-1:fx),
        nfy = fy<0?0:(fy>_height-1?_height-1:fy);
      const int x = (int)nfx, y = (int)nfy;
      const float dx = nfx - x, dy = nfy - y;
      const int
        px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=width()?width()-1:x+2,
        py = y-1<0?0:y-1, ny = dy>0?y+1:y, ay = y+2>=height()?height()-1:y+2;
      const Tfloat
        Ipp = (Tfloat)(*this)(px,py,z,c), Icp = (Tfloat)(*this)(x,py,z,c), Inp = (Tfloat)(*this)(nx,py,z,c), Iap = (Tfloat)(*this)(ax,py,z,c),
        Ip = Icp + 0.5f*(dx*(-Ipp+Inp) + dx*dx*(2*Ipp-5*Icp+4*Inp-Iap) + dx*dx*dx*(-Ipp+3*Icp-3*Inp+Iap)),
        Ipc = (Tfloat)(*this)(px,y,z,c),  Icc = (Tfloat)(*this)(x, y,z,c), Inc = (Tfloat)(*this)(nx,y,z,c),  Iac = (Tfloat)(*this)(ax,y,z,c),
        Ic = Icc + 0.5f*(dx*(-Ipc+Inc) + dx*dx*(2*Ipc-5*Icc+4*Inc-Iac) + dx*dx*dx*(-Ipc+3*Icc-3*Inc+Iac)),
        Ipn = (Tfloat)(*this)(px,ny,z,c), Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c), Ian = (Tfloat)(*this)(ax,ny,z,c),
        In = Icn + 0.5f*(dx*(-Ipn+Inn) + dx*dx*(2*Ipn-5*Icn+4*Inn-Ian) + dx*dx*dx*(-Ipn+3*Icn-3*Inn+Ian)),
        Ipa = (Tfloat)(*this)(px,ay,z,c), Ica = (Tfloat)(*this)(x,ay,z,c), Ina = (Tfloat)(*this)(nx,ay,z,c), Iaa = (Tfloat)(*this)(ax,ay,z,c),
        Ia = Ica + 0.5f*(dx*(-Ipa+Ina) + dx*dx*(2*Ipa-5*Ica+4*Ina-Iaa) + dx*dx*dx*(-Ipa+3*Ica-3*Ina+Iaa));
      return Ic + 0.5f*(dy*(-Ip+In) + dy*dy*(2*Ip-5*Ic+4*In-Ia) + dy*dy*dy*(-Ip+3*Ic-3*In+Ia));
    }

    //! Get damped pixel value, using cubic interpolation and Neumann boundary conditions for the X and Y-coordinates.
    /**
       Similar to cubic_atXY(float,float,int,int) const, except that you can specify the authorized minimum and maximum of the returned value.
    **/
    Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c,
                      const Tfloat min_value, const Tfloat max_value) const {
      const Tfloat val = cubic_atXY(fx,fy,z,c);
      return val<min_value?min_value:val>max_value?max_value:val;
    }

    Tfloat _cubic_atXY(const float fx, const float fy, const int z, const int c,
                       const Tfloat min_value, const Tfloat max_value) const {
      const Tfloat val = _cubic_atXY(fx,fy,z,c);
      return val<min_value?min_value:val>max_value?max_value:val;
    }

    //! Get pixel value, using cubic interpolation and Dirichlet boundary conditions for the X,Y and Z-coordinates.
    /**
       Similar to cubic_atX(float,int,int,int,const T) const, except that the cubic interpolation and boundary checking
       are achieved both for X,Y and Z-coordinates.
    **/
    Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const T out_value) const {
      const int
        x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2,
        y = (int)fy - (fy>=0?0:1), py = y - 1, ny = y + 1, ay = y + 2,
        z = (int)fz - (fz>=0?0:1), pz = z - 1, nz = z + 1, az = z + 2;
      const float dx = fx - x, dy = fy - y, dz = fz - z;
      const Tfloat
        Ippp = (Tfloat)atXYZ(px,py,pz,c,out_value), Icpp = (Tfloat)atXYZ(x,py,pz,c,out_value),
        Inpp = (Tfloat)atXYZ(nx,py,pz,c,out_value), Iapp = (Tfloat)atXYZ(ax,py,pz,c,out_value),
        Ipp = Icpp + 0.5f*(dx*(-Ippp+Inpp) + dx*dx*(2*Ippp-5*Icpp+4*Inpp-Iapp) + dx*dx*dx*(-Ippp+3*Icpp-3*Inpp+Iapp)),
        Ipcp = (Tfloat)atXYZ(px,y,pz,c,out_value),  Iccp = (Tfloat)atXYZ(x, y,pz,c,out_value),
        Incp = (Tfloat)atXYZ(nx,y,pz,c,out_value),  Iacp = (Tfloat)atXYZ(ax,y,pz,c,out_value),
        Icp = Iccp + 0.5f*(dx*(-Ipcp+Incp) + dx*dx*(2*Ipcp-5*Iccp+4*Incp-Iacp) + dx*dx*dx*(-Ipcp+3*Iccp-3*Incp+Iacp)),
        Ipnp = (Tfloat)atXYZ(px,ny,pz,c,out_value), Icnp = (Tfloat)atXYZ(x,ny,pz,c,out_value),
        Innp = (Tfloat)atXYZ(nx,ny,pz,c,out_value), Ianp = (Tfloat)atXYZ(ax,ny,pz,c,out_value),
        Inp = Icnp + 0.5f*(dx*(-Ipnp+Innp) + dx*dx*(2*Ipnp-5*Icnp+4*Innp-Ianp) + dx*dx*dx*(-Ipnp+3*Icnp-3*Innp+Ianp)),
        Ipap = (Tfloat)atXYZ(px,ay,pz,c,out_value), Icap = (Tfloat)atXYZ(x,ay,pz,c,out_value),
        Inap = (Tfloat)atXYZ(nx,ay,pz,c,out_value), Iaap = (Tfloat)atXYZ(ax,ay,pz,c,out_value),
        Iap = Icap + 0.5f*(dx*(-Ipap+Inap) + dx*dx*(2*Ipap-5*Icap+4*Inap-Iaap) + dx*dx*dx*(-Ipap+3*Icap-3*Inap+Iaap)),
        Ip = Icp + 0.5f*(dy*(-Ipp+Inp) + dy*dy*(2*Ipp-5*Icp+4*Inp-Iap) + dy*dy*dy*(-Ipp+3*Icp-3*Inp+Iap)),
        Ippc = (Tfloat)atXYZ(px,py,z,c,out_value), Icpc = (Tfloat)atXYZ(x,py,z,c,out_value),
        Inpc = (Tfloat)atXYZ(nx,py,z,c,out_value), Iapc = (Tfloat)atXYZ(ax,py,z,c,out_value),
        Ipc = Icpc + 0.5f*(dx*(-Ippc+Inpc) + dx*dx*(2*Ippc-5*Icpc+4*Inpc-Iapc) + dx*dx*dx*(-Ippc+3*Icpc-3*Inpc+Iapc)),
        Ipcc = (Tfloat)atXYZ(px,y,z,c,out_value),  Iccc = (Tfloat)atXYZ(x, y,z,c,out_value),
        Incc = (Tfloat)atXYZ(nx,y,z,c,out_value),  Iacc = (Tfloat)atXYZ(ax,y,z,c,out_value),
        Icc = Iccc + 0.5f*(dx*(-Ipcc+Incc) + dx*dx*(2*Ipcc-5*Iccc+4*Incc-Iacc) + dx*dx*dx*(-Ipcc+3*Iccc-3*Incc+Iacc)),
        Ipnc = (Tfloat)atXYZ(px,ny,z,c,out_value), Icnc = (Tfloat)atXYZ(x,ny,z,c,out_value),
        Innc = (Tfloat)atXYZ(nx,ny,z,c,out_value), Ianc = (Tfloat)atXYZ(ax,ny,z,c,out_value),
        Inc = Icnc + 0.5f*(dx*(-Ipnc+Innc) + dx*dx*(2*Ipnc-5*Icnc+4*Innc-Ianc) + dx*dx*dx*(-Ipnc+3*Icnc-3*Innc+Ianc)),
        Ipac = (Tfloat)atXYZ(px,ay,z,c,out_value), Icac = (Tfloat)atXYZ(x,ay,z,c,out_value),
        Inac = (Tfloat)atXYZ(nx,ay,z,c,out_value), Iaac = (Tfloat)atXYZ(ax,ay,z,c,out_value),
        Iac = Icac + 0.5f*(dx*(-Ipac+Inac) + dx*dx*(2*Ipac-5*Icac+4*Inac-Iaac) + dx*dx*dx*(-Ipac+3*Icac-3*Inac+Iaac)),
        Ic = Icc + 0.5f*(dy*(-Ipc+Inc) + dy*dy*(2*Ipc-5*Icc+4*Inc-Iac) + dy*dy*dy*(-Ipc+3*Icc-3*Inc+Iac)),
        Ippn = (Tfloat)atXYZ(px,py,nz,c,out_value), Icpn = (Tfloat)atXYZ(x,py,nz,c,out_value),
        Inpn = (Tfloat)atXYZ(nx,py,nz,c,out_value), Iapn = (Tfloat)atXYZ(ax,py,nz,c,out_value),
        Ipn = Icpn + 0.5f*(dx*(-Ippn+Inpn) + dx*dx*(2*Ippn-5*Icpn+4*Inpn-Iapn) + dx*dx*dx*(-Ippn+3*Icpn-3*Inpn+Iapn)),
        Ipcn = (Tfloat)atXYZ(px,y,nz,c,out_value),  Iccn = (Tfloat)atXYZ(x, y,nz,c,out_value),
        Incn = (Tfloat)atXYZ(nx,y,nz,c,out_value),  Iacn = (Tfloat)atXYZ(ax,y,nz,c,out_value),
        Icn = Iccn + 0.5f*(dx*(-Ipcn+Incn) + dx*dx*(2*Ipcn-5*Iccn+4*Incn-Iacn) + dx*dx*dx*(-Ipcn+3*Iccn-3*Incn+Iacn)),
        Ipnn = (Tfloat)atXYZ(px,ny,nz,c,out_value), Icnn = (Tfloat)atXYZ(x,ny,nz,c,out_value),
        Innn = (Tfloat)atXYZ(nx,ny,nz,c,out_value), Iann = (Tfloat)atXYZ(ax,ny,nz,c,out_value),
        Inn = Icnn + 0.5f*(dx*(-Ipnn+Innn) + dx*dx*(2*Ipnn-5*Icnn+4*Innn-Iann) + dx*dx*dx*(-Ipnn+3*Icnn-3*Innn+Iann)),
        Ipan = (Tfloat)atXYZ(px,ay,nz,c,out_value), Ican = (Tfloat)atXYZ(x,ay,nz,c,out_value),
        Inan = (Tfloat)atXYZ(nx,ay,nz,c,out_value), Iaan = (Tfloat)atXYZ(ax,ay,nz,c,out_value),
        Ian = Ican + 0.5f*(dx*(-Ipan+Inan) + dx*dx*(2*Ipan-5*Ican+4*Inan-Iaan) + dx*dx*dx*(-Ipan+3*Ican-3*Inan+Iaan)),
        In = Icn + 0.5f*(dy*(-Ipn+Inn) + dy*dy*(2*Ipn-5*Icn+4*Inn-Ian) + dy*dy*dy*(-Ipn+3*Icn-3*Inn+Ian)),
        Ippa = (Tfloat)atXYZ(px,py,az,c,out_value), Icpa = (Tfloat)atXYZ(x,py,az,c,out_value),
        Inpa = (Tfloat)atXYZ(nx,py,az,c,out_value), Iapa = (Tfloat)atXYZ(ax,py,az,c,out_value),
        Ipa = Icpa + 0.5f*(dx*(-Ippa+Inpa) + dx*dx*(2*Ippa-5*Icpa+4*Inpa-Iapa) + dx*dx*dx*(-Ippa+3*Icpa-3*Inpa+Iapa)),
        Ipca = (Tfloat)atXYZ(px,y,az,c,out_value),  Icca = (Tfloat)atXYZ(x, y,az,c,out_value),
        Inca = (Tfloat)atXYZ(nx,y,az,c,out_value),  Iaca = (Tfloat)atXYZ(ax,y,az,c,out_value),
        Ica = Icca + 0.5f*(dx*(-Ipca+Inca) + dx*dx*(2*Ipca-5*Icca+4*Inca-Iaca) + dx*dx*dx*(-Ipca+3*Icca-3*Inca+Iaca)),
        Ipna = (Tfloat)atXYZ(px,ny,az,c,out_value), Icna = (Tfloat)atXYZ(x,ny,az,c,out_value),
        Inna = (Tfloat)atXYZ(nx,ny,az,c,out_value), Iana = (Tfloat)atXYZ(ax,ny,az,c,out_value),
        Ina = Icna + 0.5f*(dx*(-Ipna+Inna) + dx*dx*(2*Ipna-5*Icna+4*Inna-Iana) + dx*dx*dx*(-Ipna+3*Icna-3*Inna+Iana)),
        Ipaa = (Tfloat)atXYZ(px,ay,az,c,out_value), Icaa = (Tfloat)atXYZ(x,ay,az,c,out_value),
        Inaa = (Tfloat)atXYZ(nx,ay,az,c,out_value), Iaaa = (Tfloat)atXYZ(ax,ay,az,c,out_value),
        Iaa = Icaa + 0.5f*(dx*(-Ipaa+Inaa) + dx*dx*(2*Ipaa-5*Icaa+4*Inaa-Iaaa) + dx*dx*dx*(-Ipaa+3*Icaa-3*Inaa+Iaaa)),
        Ia = Ica + 0.5f*(dy*(-Ipa+Ina) + dy*dy*(2*Ipa-5*Ica+4*Ina-Iaa) + dy*dy*dy*(-Ipa+3*Ica-3*Ina+Iaa));
      return Ic + 0.5f*(dz*(-Ip+In) + dz*dz*(2*Ip-5*Ic+4*In-Ia) + dz*dz*dz*(-Ip+3*Ic-3*In+Ia));
    }

    //! Get damped pixel value, using cubic interpolation and Dirichlet boundary conditions for the X,Y and Z-coordinates.
    /**
       Similar to cubic_atXYZ(float,float,float,int,const T) const, except that you can specify the authorized minimum and maximum of the returned value.
    **/
    Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const T out_value,
                       const Tfloat min_value, const Tfloat max_value) const {
      const Tfloat val = cubic_atXYZ(fx,fy,fz,c,out_value);
      return val<min_value?min_value:val>max_value?max_value:val;
    }

    //! Get pixel value, using cubic interpolation and Neumann boundary conditions for the X,Y and Z-coordinates.
    /**
       Similar to cubic_atX(float,int,int,int) const, except that the cubic interpolation and boundary checking
       are achieved both for X,Y and Z-coordinates.
       \note
       - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _cubic_atXYZ(float,float,float,int).
    **/
    Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c=0) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "cubic_atXYZ() : Empty instance.",
                                    cimg_instance);
      return _cubic_atXYZ(fx,fy,fz,c);
    }

    Tfloat _cubic_atXYZ(const float fx, const float fy, const float fz, const int c=0) const {
      const float
        nfx = fx<0?0:(fx>_width-1?_width-1:fx),
        nfy = fy<0?0:(fy>_height-1?_height-1:fy),
        nfz = fz<0?0:(fz>_depth-1?_depth-1:fz);
      const int x = (int)nfx, y = (int)nfy, z = (int)nfz;
      const float dx = nfx - x, dy = nfy - y, dz = nfz - z;
      const int
        px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=width()?width()-1:x+2,
        py = y-1<0?0:y-1, ny = dy>0?y+1:y, ay = y+2>=height()?height()-1:y+2,
        pz = z-1<0?0:z-1, nz = dz>0?z+1:z, az = z+2>=depth()?depth()-1:z+2;
      const Tfloat
        Ippp = (Tfloat)(*this)(px,py,pz,c), Icpp = (Tfloat)(*this)(x,py,pz,c),
        Inpp = (Tfloat)(*this)(nx,py,pz,c), Iapp = (Tfloat)(*this)(ax,py,pz,c),
        Ipp = Icpp + 0.5f*(dx*(-Ippp+Inpp) + dx*dx*(2*Ippp-5*Icpp+4*Inpp-Iapp) + dx*dx*dx*(-Ippp+3*Icpp-3*Inpp+Iapp)),
        Ipcp = (Tfloat)(*this)(px,y,pz,c),  Iccp = (Tfloat)(*this)(x, y,pz,c),
        Incp = (Tfloat)(*this)(nx,y,pz,c),  Iacp = (Tfloat)(*this)(ax,y,pz,c),
        Icp = Iccp + 0.5f*(dx*(-Ipcp+Incp) + dx*dx*(2*Ipcp-5*Iccp+4*Incp-Iacp) + dx*dx*dx*(-Ipcp+3*Iccp-3*Incp+Iacp)),
        Ipnp = (Tfloat)(*this)(px,ny,pz,c), Icnp = (Tfloat)(*this)(x,ny,pz,c),
        Innp = (Tfloat)(*this)(nx,ny,pz,c), Ianp = (Tfloat)(*this)(ax,ny,pz,c),
        Inp = Icnp + 0.5f*(dx*(-Ipnp+Innp) + dx*dx*(2*Ipnp-5*Icnp+4*Innp-Ianp) + dx*dx*dx*(-Ipnp+3*Icnp-3*Innp+Ianp)),
        Ipap = (Tfloat)(*this)(px,ay,pz,c), Icap = (Tfloat)(*this)(x,ay,pz,c),
        Inap = (Tfloat)(*this)(nx,ay,pz,c), Iaap = (Tfloat)(*this)(ax,ay,pz,c),
        Iap = Icap + 0.5f*(dx*(-Ipap+Inap) + dx*dx*(2*Ipap-5*Icap+4*Inap-Iaap) + dx*dx*dx*(-Ipap+3*Icap-3*Inap+Iaap)),
        Ip = Icp + 0.5f*(dy*(-Ipp+Inp) + dy*dy*(2*Ipp-5*Icp+4*Inp-Iap) + dy*dy*dy*(-Ipp+3*Icp-3*Inp+Iap)),
        Ippc = (Tfloat)(*this)(px,py,z,c), Icpc = (Tfloat)(*this)(x,py,z,c),
        Inpc = (Tfloat)(*this)(nx,py,z,c), Iapc = (Tfloat)(*this)(ax,py,z,c),
        Ipc = Icpc + 0.5f*(dx*(-Ippc+Inpc) + dx*dx*(2*Ippc-5*Icpc+4*Inpc-Iapc) + dx*dx*dx*(-Ippc+3*Icpc-3*Inpc+Iapc)),
        Ipcc = (Tfloat)(*this)(px,y,z,c),  Iccc = (Tfloat)(*this)(x, y,z,c),
        Incc = (Tfloat)(*this)(nx,y,z,c),  Iacc = (Tfloat)(*this)(ax,y,z,c),
        Icc = Iccc + 0.5f*(dx*(-Ipcc+Incc) + dx*dx*(2*Ipcc-5*Iccc+4*Incc-Iacc) + dx*dx*dx*(-Ipcc+3*Iccc-3*Incc+Iacc)),
        Ipnc = (Tfloat)(*this)(px,ny,z,c), Icnc = (Tfloat)(*this)(x,ny,z,c),
        Innc = (Tfloat)(*this)(nx,ny,z,c), Ianc = (Tfloat)(*this)(ax,ny,z,c),
        Inc = Icnc + 0.5f*(dx*(-Ipnc+Innc) + dx*dx*(2*Ipnc-5*Icnc+4*Innc-Ianc) + dx*dx*dx*(-Ipnc+3*Icnc-3*Innc+Ianc)),
        Ipac = (Tfloat)(*this)(px,ay,z,c), Icac = (Tfloat)(*this)(x,ay,z,c),
        Inac = (Tfloat)(*this)(nx,ay,z,c), Iaac = (Tfloat)(*this)(ax,ay,z,c),
        Iac = Icac + 0.5f*(dx*(-Ipac+Inac) + dx*dx*(2*Ipac-5*Icac+4*Inac-Iaac) + dx*dx*dx*(-Ipac+3*Icac-3*Inac+Iaac)),
        Ic = Icc + 0.5f*(dy*(-Ipc+Inc) + dy*dy*(2*Ipc-5*Icc+4*Inc-Iac) + dy*dy*dy*(-Ipc+3*Icc-3*Inc+Iac)),
        Ippn = (Tfloat)(*this)(px,py,nz,c), Icpn = (Tfloat)(*this)(x,py,nz,c),
        Inpn = (Tfloat)(*this)(nx,py,nz,c), Iapn = (Tfloat)(*this)(ax,py,nz,c),
        Ipn = Icpn + 0.5f*(dx*(-Ippn+Inpn) + dx*dx*(2*Ippn-5*Icpn+4*Inpn-Iapn) + dx*dx*dx*(-Ippn+3*Icpn-3*Inpn+Iapn)),
        Ipcn = (Tfloat)(*this)(px,y,nz,c),  Iccn = (Tfloat)(*this)(x, y,nz,c),
        Incn = (Tfloat)(*this)(nx,y,nz,c),  Iacn = (Tfloat)(*this)(ax,y,nz,c),
        Icn = Iccn + 0.5f*(dx*(-Ipcn+Incn) + dx*dx*(2*Ipcn-5*Iccn+4*Incn-Iacn) + dx*dx*dx*(-Ipcn+3*Iccn-3*Incn+Iacn)),
        Ipnn = (Tfloat)(*this)(px,ny,nz,c), Icnn = (Tfloat)(*this)(x,ny,nz,c),
        Innn = (Tfloat)(*this)(nx,ny,nz,c), Iann = (Tfloat)(*this)(ax,ny,nz,c),
        Inn = Icnn + 0.5f*(dx*(-Ipnn+Innn) + dx*dx*(2*Ipnn-5*Icnn+4*Innn-Iann) + dx*dx*dx*(-Ipnn+3*Icnn-3*Innn+Iann)),
        Ipan = (Tfloat)(*this)(px,ay,nz,c), Ican = (Tfloat)(*this)(x,ay,nz,c),
        Inan = (Tfloat)(*this)(nx,ay,nz,c), Iaan = (Tfloat)(*this)(ax,ay,nz,c),
        Ian = Ican + 0.5f*(dx*(-Ipan+Inan) + dx*dx*(2*Ipan-5*Ican+4*Inan-Iaan) + dx*dx*dx*(-Ipan+3*Ican-3*Inan+Iaan)),
        In = Icn + 0.5f*(dy*(-Ipn+Inn) + dy*dy*(2*Ipn-5*Icn+4*Inn-Ian) + dy*dy*dy*(-Ipn+3*Icn-3*Inn+Ian)),
        Ippa = (Tfloat)(*this)(px,py,az,c), Icpa = (Tfloat)(*this)(x,py,az,c),
        Inpa = (Tfloat)(*this)(nx,py,az,c), Iapa = (Tfloat)(*this)(ax,py,az,c),
        Ipa = Icpa + 0.5f*(dx*(-Ippa+Inpa) + dx*dx*(2*Ippa-5*Icpa+4*Inpa-Iapa) + dx*dx*dx*(-Ippa+3*Icpa-3*Inpa+Iapa)),
        Ipca = (Tfloat)(*this)(px,y,az,c),  Icca = (Tfloat)(*this)(x, y,az,c),
        Inca = (Tfloat)(*this)(nx,y,az,c),  Iaca = (Tfloat)(*this)(ax,y,az,c),
        Ica = Icca + 0.5f*(dx*(-Ipca+Inca) + dx*dx*(2*Ipca-5*Icca+4*Inca-Iaca) + dx*dx*dx*(-Ipca+3*Icca-3*Inca+Iaca)),
        Ipna = (Tfloat)(*this)(px,ny,az,c), Icna = (Tfloat)(*this)(x,ny,az,c),
        Inna = (Tfloat)(*this)(nx,ny,az,c), Iana = (Tfloat)(*this)(ax,ny,az,c),
        Ina = Icna + 0.5f*(dx*(-Ipna+Inna) + dx*dx*(2*Ipna-5*Icna+4*Inna-Iana) + dx*dx*dx*(-Ipna+3*Icna-3*Inna+Iana)),
        Ipaa = (Tfloat)(*this)(px,ay,az,c), Icaa = (Tfloat)(*this)(x,ay,az,c),
        Inaa = (Tfloat)(*this)(nx,ay,az,c), Iaaa = (Tfloat)(*this)(ax,ay,az,c),
        Iaa = Icaa + 0.5f*(dx*(-Ipaa+Inaa) + dx*dx*(2*Ipaa-5*Icaa+4*Inaa-Iaaa) + dx*dx*dx*(-Ipaa+3*Icaa-3*Inaa+Iaaa)),
        Ia = Ica + 0.5f*(dy*(-Ipa+Ina) + dy*dy*(2*Ipa-5*Ica+4*Ina-Iaa) + dy*dy*dy*(-Ipa+3*Ica-3*Ina+Iaa));
      return Ic + 0.5f*(dz*(-Ip+In) + dz*dz*(2*Ip-5*Ic+4*In-Ia) + dz*dz*dz*(-Ip+3*Ic-3*In+Ia));
    }

    //! Get damped pixel value, using cubic interpolation and Neumann boundary conditions for the X,Y and Z-coordinates.
    /**
       Similar to cubic_atXYZ(float,float,float,int) const, except that you can specify the authorized minimum and maximum of the returned value.
    **/
    Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c,
                       const Tfloat min_value, const Tfloat max_value) const {
      const Tfloat val = cubic_atXYZ(fx,fy,fz,c);
      return val<min_value?min_value:val>max_value?max_value:val;
    }

    Tfloat _cubic_atXYZ(const float fx, const float fy, const float fz, const int c,
                        const Tfloat min_value, const Tfloat max_value) const {
      const Tfloat val = _cubic_atXYZ(fx,fy,fz,c);
      return val<min_value?min_value:val>max_value?max_value:val;
    }

    //! Set pixel value, using linear interpolation for the X and Y-coordinates.
    /**
       Set pixel value at specified coordinates (\c fx,\c fy,\c z,\c c) in the image instance, in a way that the value is spread
       amongst several neighbors if the pixel coordinates are indeed float-valued.
       \param value : Pixel value to set.
       \param fx : X-coordinate of the pixel value (float-valued).
       \param fy : Y-coordinate of the pixel value (float-valued).
       \param z : Z-coordinate of the pixel value.
       \param c : C-coordinate of the pixel value.
       \param is_added : Boolean telling if the pixel value is added to (\c true), or simply replace (\c false) the current image pixel(s).
       \return A reference to the current image instance.
       \note
       - If specified coordinates are outside image bounds, no operations are performed.
       \sa linear_atXY(),
           set_linear_atXYZ().
    **/
    CImg<T>& set_linear_atXY(const T& value, const float fx, const float fy=0, const int z=0, const int c=0,
                             const bool is_added=false) {
      const int
        x = (int)fx - (fx>=0?0:1), nx = x + 1,
        y = (int)fy - (fy>=0?0:1), ny = y + 1;
      const float
        dx = fx - x,
        dy = fy - y;
      if (z>=0 && z<depth() && c>=0 && c<spectrum()) {
        if (y>=0 && y<height()) {
          if (x>=0 && x<width()) {
            const float w1 = (1-dx)*(1-dy), w2 = is_added?1:(1-w1);
            (*this)(x,y,z,c) = (T)(w1*value + w2*(*this)(x,y,z,c));
          }
          if (nx>=0 && nx<width()) {
            const float w1 = dx*(1-dy), w2 = is_added?1:(1-w1);
            (*this)(nx,y,z,c) = (T)(w1*value + w2*(*this)(nx,y,z,c));
          }
        }
        if (ny>=0 && ny<height()) {
          if (x>=0 && x<width()) {
            const float w1 = (1-dx)*dy, w2 = is_added?1:(1-w1);
            (*this)(x,ny,z,c) = (T)(w1*value + w2*(*this)(x,ny,z,c));
          }
          if (nx>=0 && nx<width()) {
            const float w1 = dx*dy, w2 = is_added?1:(1-w1);
            (*this)(nx,ny,z,c) = (T)(w1*value + w2*(*this)(nx,ny,z,c));
          }
        }
      }
      return *this;
    }

    //! Set pixel value, using linear interpolation for the X,Y and Z-coordinates.
    /**
       Similar to set_linear_atXY(const T&,float,float,int,int,bool), except that the linear interpolation
       is achieved both for X,Y and Z-coordinates.
    **/
    CImg<T>& set_linear_atXYZ(const T& value, const float fx, const float fy=0, const float fz=0, const int c=0,
                              const bool is_added=false) {
      const int
        x = (int)fx - (fx>=0?0:1), nx = x + 1,
        y = (int)fy - (fy>=0?0:1), ny = y + 1,
        z = (int)fz - (fz>=0?0:1), nz = z + 1;
      const float
        dx = fx - x,
        dy = fy - y,
        dz = fz - z;
      if (c>=0 && c<spectrum()) {
        if (z>=0 && z<depth()) {
          if (y>=0 && y<height()) {
            if (x>=0 && x<width()) {
              const float w1 = (1-dx)*(1-dy)*(1-dz), w2 = is_added?1:(1-w1);
              (*this)(x,y,z,c) = (T)(w1*value + w2*(*this)(x,y,z,c));
            }
            if (nx>=0 && nx<width()) {
              const float w1 = dx*(1-dy)*(1-dz), w2 = is_added?1:(1-w1);
              (*this)(nx,y,z,c) = (T)(w1*value + w2*(*this)(nx,y,z,c));
            }
          }
          if (ny>=0 && ny<height()) {
            if (x>=0 && x<width()) {
              const float w1 = (1-dx)*dy*(1-dz), w2 = is_added?1:(1-w1);
              (*this)(x,ny,z,c) = (T)(w1*value + w2*(*this)(x,ny,z,c));
            }
            if (nx>=0 && nx<width()) {
              const float w1 = dx*dy*(1-dz), w2 = is_added?1:(1-w1);
              (*this)(nx,ny,z,c) = (T)(w1*value + w2*(*this)(nx,ny,z,c));
            }
          }
        }
        if (nz>=0 && nz<depth()) {
          if (y>=0 && y<height()) {
            if (x>=0 && x<width()) {
              const float w1 = (1-dx)*(1-dy), w2 = is_added?1:(1-w1);
              (*this)(x,y,nz,c) = (T)(w1*value + w2*(*this)(x,y,nz,c));
            }
            if (nx>=0 && nx<width()) {
              const float w1 = dx*(1-dy), w2 = is_added?1:(1-w1);
              (*this)(nx,y,nz,c) = (T)(w1*value + w2*(*this)(nx,y,nz,c));
            }
          }
          if (ny>=0 && ny<height()) {
            if (x>=0 && x<width()) {
              const float w1 = (1-dx)*dy, w2 = is_added?1:(1-w1);
              (*this)(x,ny,nz,c) = (T)(w1*value + w2*(*this)(x,ny,nz,c));
            }
            if (nx>=0 && nx<width()) {
              const float w1 = dx*dy, w2 = is_added?1:(1-w1);
              (*this)(nx,ny,nz,c) = (T)(w1*value + w2*(*this)(nx,ny,nz,c));
            }
          }
        }
      }
      return *this;
    }

    //! Get a C-string containing a list of all values of the image instance.
    /**
       Return a new \c CImg<char> image whose buffer data() is a \c char* string describing the list of all pixel values
       of the image instance (written in base 10), separated by specified \c separator character.
       \param separator : a \c char character which specifies the separator between values in the returned C-string.
       \param max_size : Maximum size of the returned image.
       \note
       - The returned image is never empty.
       - For an empty image instance, the returned string is <tt>""</tt>.
       - If \c max_size is equal to \c 0, there are no limits on the size of the returned string.
       - Otherwise, if the maximum number of string characters is exceeded, the value string is cut off
         and terminated by character \c '\0'. In that case, the returned image size is <tt>max_size + 1</tt>.
       \sa pixel_type().
    **/
    CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const {
      if (is_empty()) return CImg<charT>(1,1,1,1,0);
      CImgList<charT> items;
      char s_item[256] = { 0 };
      const T *ptrs = _data;
      unsigned int string_size = 0;
      for (unsigned int off = 0, siz = (unsigned int)size(); off<siz && string_size<=max_size; ++off) {
        const unsigned int printed_size = 1U + cimg_snprintf(s_item,sizeof(s_item),cimg::type<T>::format(),cimg::type<T>::format(*(ptrs++)));
        CImg<charT> item(s_item,printed_size);
        item[printed_size-1] = separator;
        item.move_to(items);
        if (max_size) string_size+=printed_size;
      }
      CImg<charT> res;
      (items>'x').move_to(res);
      if (max_size && res._width>max_size) res.crop(0,max_size);
      res.back() = 0;
      return res;
    }

    //@}
    //-------------------------------------
    //
    //! \name Instance Checking
    //@{
    //-------------------------------------

    //! Test shared state of the pixel buffer.
    /**
       Return \c true if image instance has a shared memory buffer, and \c false otherwise.
       \note
       - A shared image do not own his pixel buffer data() and will not deallocate it on destruction.
       - Most of the time, a \c CImg<T> image instance will \e not be shared.
       - A shared image can only be obtained by a limited set of constructors and methods (see list below).
       \sa CImg(const t *const,unsigned int,unsigned int,unsigned int,unsigned int,bool),
           CImg(const CImg<t>&),
           CImg(const CImg<t>&,bool),
           assign(const t *const,unsigned int,unsigned int,unsigned int,unsigned int,bool),
           get_shared_points(),
           get_shared_line(),
           get_shared_lines(),
           get_shared_plane(),
           get_shared_planes(),
           get_shared_channel(),
           get_shared_channels(),
           get_shared().
    **/
    bool is_shared() const {
      return _is_shared;
    }

    //! Test if image instance is empty.
    /**
       Return \c true, if image instance is empty, i.e. does \e not contain any pixel values, has dimensions \c 0 x \c 0 x \c 0 x \c 0
       and a pixel buffer pointer set to \c 0 (null pointer), and \c false otherwise.
       \sa CImg(),
           assign().
    **/
    bool is_empty() const {
      return !(_data && _width && _height && _depth && _spectrum);
    }

    //! Test if image width is equal to a specified value.
    /**
       Return \c true if image instance has \c size_x columns, and \c false otherwise.
       \param size_x : Desired width to test with.
       \note
       - Return the boolean <tt>width()==size_x</tt>.
       \sa is_sameX(const CImg<t>&) const,
           is_sameX(const CImgDisplay&) const,
           is_sameY(unsigned int) const,
           is_sameZ(unsigned int) const,
           is_sameC(unsigned int) const,
           is_sameXY(unsigned int,unsigned int) const,
           is_sameXYZ(unsigned int,unsigned int,unsigned int) const,
           is_sameXYZC(unsigned int,unsigned int,unsigned int,unsigned int) const.
    **/
    bool is_sameX(const unsigned int size_x) const {
      return (_width==size_x);
    }

    //! Test if image width is the same as that of another image.
    /**
       Return \c true if image instance has \c img.width() columns, and \c false otherwise.
       \param img : Input image to test width() with.
       \note
       - Return the boolean <tt>width()==img.width()</tt>.
       \sa is_sameX(unsigned int) const,
           is_sameX(const CImgDisplay&) const,
           is_sameY(const CImg<t>&) const,
           is_sameZ(const CImg<t>&) const,
           is_sameC(const CImg<t>&) const,
           is_sameXY(const CImg<t>&) const,
           is_sameXYZ(const CImg<t>&) const,
           is_sameXYZC(const CImg<t>&) const.
    **/
    template<typename t>
    bool is_sameX(const CImg<t>& img) const {
      return is_sameX(img._width);
    }

    //! Test if image width is the same as that of an existing display window.
    /**
       Return \c true if image instance has \c disp.width() columns, and \c false otherwise.
       \param disp : Input display window to test width() with.
       \note
       - Return the boolean <tt>width()==disp.width()</tt>.
       \sa is_sameX(unsigned int) const,
           is_sameX(const CImg<t>&) const,
           is_sameY(const CImgDisplay&) const,
           is_sameXY(const CImgDisplay&) const,
    **/
    bool is_sameX(const CImgDisplay& disp) const {
      return is_sameX((unsigned int)disp.width());
    }

    //! Test if image height is equal to a specified value.
    /**
       Similar to is_sameX(unsigned int) const, except that the test focuses on the image height().
    **/
    bool is_sameY(const unsigned int size_y) const {
      return (_height==size_y);
    }

    //! Test if image height is the same as that of another image.
    /**
       Similar to is_sameX(const CImg<t>&) const, except that the test focuses on the image height().
    **/
    template<typename t>
    bool is_sameY(const CImg<t>& img) const {
      return is_sameY(img._height);
    }

    //! Test if image height is the same as that of an existing display window.
    /**
       Similar to is_sameX(const CImgDisplay&) const, except that the test focuses on the image height().
    **/
    bool is_sameY(const CImgDisplay& disp) const {
      return is_sameY((unsigned int)disp.height());
    }

    //! Test if image depth is equal to a specified value.
    /**
       Similar to is_sameX(unsigned int) const, except that the test focuses on the image depth().
    **/
    bool is_sameZ(const unsigned int size_z) const {
      return (_depth==size_z);
    }

    //! Test if image depth is the same as that of another image.
    /**
       Similar to is_sameX(const CImg<t>&) const, except that the test focuses on the image depth().
    **/
    template<typename t>
    bool is_sameZ(const CImg<t>& img) const {
      return is_sameZ(img._depth);
    }

    //! Test if image spectrum is equal to a specified value.
    /**
       Similar to is_sameX(unsigned int) const, except that the test focuses on the image spectrum().
    **/
    bool is_sameC(const unsigned int size_c) const {
      return (_spectrum==size_c);
    }

    //! Test if image spectrum is the same as that of another image.
    /**
       Similar to is_sameX(const CImg<t>&) const, except that the test focuses on the image spectrum().
    **/
    template<typename t>
    bool is_sameC(const CImg<t>& img) const {
      return is_sameC(img._spectrum);
    }

    //! Test if image width and height are equal to specified values.
    /**
       Test if is_sameX(unsigned int) const and is_sameY(unsigned int) const are both verified.
    **/
    bool is_sameXY(const unsigned int size_x, const unsigned int size_y) const {
      return (is_sameX(size_x) && is_sameY(size_y));
    }

    //! Test if image width and height are the same as that of another image.
    /**
       Test if is_sameX(const CImg<t>&) const and is_sameY(const CImg<t>&) const are both verified.
    **/
    template<typename t>
    bool is_sameXY(const CImg<t>& img) const {
      return (is_sameX(img) && is_sameY(img));
    }

    //! Test if image width and height are the same as that of an existing display window.
    /**
       Test if is_sameX(const CImgDisplay&) const and is_sameY(const CImgDisplay&) const are both verified.
    **/
    bool is_sameXY(const CImgDisplay& disp) const {
      return (is_sameX(disp) && is_sameY(disp));
    }

    //! Test if image width and depth are equal to specified values.
    /**
       Test if is_sameX(unsigned int) const and is_sameZ(unsigned int) const are both verified.
    **/
    bool is_sameXZ(const unsigned int size_x, const unsigned int size_z) const {
      return (is_sameX(size_x) && is_sameZ(size_z));
    }

    //! Test if image width and depth are the same as that of another image.
    /**
       Test if is_sameX(const CImg<t>&) const and is_sameZ(const CImg<t>&) const are both verified.
    **/
    template<typename t>
    bool is_sameXZ(const CImg<t>& img) const {
      return (is_sameX(img) && is_sameZ(img));
    }

    //! Test if image width and spectrum are equal to specified values.
    /**
       Test if is_sameX(unsigned int) const and is_sameC(unsigned int) const are both verified.
    **/
    bool is_sameXC(const unsigned int size_x, const unsigned int size_c) const {
      return (is_sameX(size_x) && is_sameC(size_c));
    }

    //! Test if image width and spectrum are the same as that of another image.
    /**
       Test if is_sameX(const CImg<t>&) const and is_sameC(const CImg<t>&) const are both verified.
    **/
    template<typename t>
    bool is_sameXC(const CImg<t>& img) const {
      return (is_sameX(img) && is_sameC(img));
    }

    //! Test if image height and depth are equal to specified values.
    /**
       Test if is_sameY(unsigned int) const and is_sameZ(unsigned int) const are both verified.
    **/
    bool is_sameYZ(const unsigned int size_y, const unsigned int size_z) const {
      return (is_sameY(size_y) && is_sameZ(size_z));
    }

    //! Test if image height and depth are the same as that of another image.
    /**
       Test if is_sameY(const CImg<t>&) const and is_sameZ(const CImg<t>&) const are both verified.
    **/
    template<typename t>
    bool is_sameYZ(const CImg<t>& img) const {
      return (is_sameY(img) && is_sameZ(img));
    }

    //! Test if image height and spectrum are equal to specified values.
    /**
       Test if is_sameY(unsigned int) const and is_sameC(unsigned int) const are both verified.
    **/
    bool is_sameYC(const unsigned int size_y, const unsigned int size_c) const {
      return (is_sameY(size_y) && is_sameC(size_c));
    }

    //! Test if image height and spectrum are the same as that of another image.
    /**
       Test if is_sameY(const CImg<t>&) const and is_sameC(const CImg<t>&) const are both verified.
    **/
    template<typename t>
    bool is_sameYC(const CImg<t>& img) const {
      return (is_sameY(img) && is_sameC(img));
    }

    //! Test if image depth and spectrum are equal to specified values.
    /**
       Test if is_sameZ(unsigned int) const and is_sameC(unsigned int) const are both verified.
    **/
    bool is_sameZC(const unsigned int size_z, const unsigned int size_c) const {
      return (is_sameZ(size_z) && is_sameC(size_c));
    }

    //! Test if image depth and spectrum are the same as that of another image.
    /**
       Test if is_sameZ(const CImg<t>&) const and is_sameC(const CImg<t>&) const are both verified.
    **/
    template<typename t>
    bool is_sameZC(const CImg<t>& img) const {
      return (is_sameZ(img) && is_sameC(img));
    }

    //! Test if image width, height and depth are equal to specified values.
    /**
       Test if is_sameXY(unsigned int,unsigned int) const and is_sameZ(unsigned int) const are both verified.
    **/
    bool is_sameXYZ(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z) const {
      return (is_sameXY(size_x,size_y) && is_sameZ(size_z));
    }

    //! Test if image width, height and depth are the same as that of another image.
    /**
       Test if is_sameXY(const CImg<t>&) const and is_sameZ(const CImg<t>&) const are both verified.
    **/
    template<typename t>
    bool is_sameXYZ(const CImg<t>& img) const {
      return (is_sameXY(img) && is_sameZ(img));
    }

    //! Test if image width, height and spectrum are equal to specified values.
    /**
       Test if is_sameXY(unsigned int,unsigned int) const and is_sameC(unsigned int) const are both verified.
    **/
    bool is_sameXYC(const unsigned int size_x, const unsigned int size_y, const unsigned int size_c) const {
      return (is_sameXY(size_x,size_y) && is_sameC(size_c));
    }

    //! Test if image width, height and spectrum are the same as that of another image.
    /**
       Test if is_sameXY(const CImg<t>&) const and is_sameC(const CImg<t>&) const are both verified.
    **/
    template<typename t>
    bool is_sameXYC(const CImg<t>& img) const {
      return (is_sameXY(img) && is_sameC(img));
    }

    //! Test if image width, depth and spectrum are equal to specified values.
    /**
       Test if is_sameXZ(unsigned int,unsigned int) const and is_sameC(unsigned int) const are both verified.
    **/
    bool is_sameXZC(const unsigned int size_x, const unsigned int size_z, const unsigned int size_c) const {
      return (is_sameXZ(size_x,size_z) && is_sameC(size_c));
    }

    //! Test if image width, depth and spectrum are the same as that of another image.
    /**
       Test if is_sameXZ(const CImg<t>&) const and is_sameC(const CImg<t>&) const are both verified.
    **/
    template<typename t>
    bool is_sameXZC(const CImg<t>& img) const {
      return (is_sameXZ(img) && is_sameC(img));
    }

    //! Test if image height, depth and spectrum are equal to specified values.
    /**
       Test if is_sameYZ(unsigned int,unsigned int) const and is_sameC(unsigned int) const are both verified.
    **/
    bool is_sameYZC(const unsigned int size_y, const unsigned int size_z, const unsigned int size_c) const {
      return (is_sameYZ(size_y,size_z) && is_sameC(size_c));
    }

    //! Test if image height, depth and spectrum are the same as that of another image.
    /**
       Test if is_sameYZ(const CImg<t>&) const and is_sameC(const CImg<t>&) const are both verified.
    **/
    template<typename t>
    bool is_sameYZC(const CImg<t>& img) const {
      return (is_sameYZ(img) && is_sameC(img));
    }

    //! Test if image width, height, depth and spectrum are equal to specified values.
    /**
       Test if is_sameXYZ(unsigned int,unsigned int,unsigned int) const and is_sameC(unsigned int) const are both verified.
    **/
    bool is_sameXYZC(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c) const {
      return (is_sameXYZ(size_x,size_y,size_z) && is_sameC(size_c));
    }

    //! Test if image width, height, depth and spectrum are the same as that of another image.
    /**
       Test if is_sameXYZ(const CImg<t>&) const and is_sameC(const CImg<t>&) const are both verified.
    **/
    template<typename t>
    bool is_sameXYZC(const CImg<t>& img) const {
      return (is_sameXYZ(img) && is_sameC(img));
    }

    //! Test if specified coordinates are inside image bounds.
    /**
       Return \c true if pixel located at (\c x,\c y,\c z,\c c) is inside bounds of the image instance, and \c false otherwise.
       \param x : X-coordinate of the pixel value.
       \param y : Y-coordinate of the pixel value.
       \param z : Z-coordinate of the pixel value.
       \param c : C-coordinate of the pixel value.
       \note
       - Return \c true only if all these conditions are verified :
         - The image instance is \e not empty.
         - <tt>0<=x<=\ref width()-1</tt>.
         - <tt>0<=y<=\ref height()-1</tt>.
         - <tt>0<=z<=\ref depth()-1</tt>.
         - <tt>0<=c<=\ref spectrum()-1</tt>.
       \sa contains(const T&,t&,t&,t&,t&) const,
           contains(const T&,t&,t&,t&) const,
           contains(const T&,t&,t&) const,
           contains(const T&,t&) const,
           contains(const T&) const.
    **/
    bool containsXYZC(const int x, const int y=0, const int z=0, const int c=0) const {
      return !is_empty() && x>=0 && x<width() && y>=0 && y<height() && z>=0 && z<depth() && c>=0 && c<spectrum();
    }

    //! Test if pixel value is inside image bounds and get its X,Y,Z and C-coordinates.
    /**
       Return \c true, if specified reference refers to a pixel value inside bounds of the image instance, and \c false otherwise.
       \param pixel : Reference to pixel value to test.
       \param[out] x : X-coordinate of the pixel value, if test succeeds.
       \param[out] y : Y-coordinate of the pixel value, if test succeeds.
       \param[out] z : Z-coordinate of the pixel value, if test succeeds.
       \param[out] c : C-coordinate of the pixel value, if test succeeds.
       \note
       - Useful to convert an offset to a  buffer value into pixel value coordinates :
       \code
       const CImg<float> img(100,100,1,3);      // Construct a 100x100 RGB color image.
       const unsigned int offset = 1249;        // Offset to the pixel (49,12,0,0).
       unsigned int x,y,z,c;
       if (img.contains(img[offset],x,y,z,c)) { // Convert offset to (x,y,z,c) coordinates.
         std::printf("Offset %u refers to pixel located at (%u,%u,%u,%u).\n",
                     offset,x,y,z,c);
       }
       \endcode
       \sa containsXYZC(int,int,int,int) const,
           contains(const T&,t&,t&,t&) const,
           contains(const T&,t&,t&) const,
           contains(const T&,t&) const,
           contains(const T&) const.
    **/
    template<typename t>
    bool contains(const T& pixel, t& x, t& y, t& z, t& c) const {
      const unsigned int wh = _width*_height, whd = wh*_depth, siz = whd*_spectrum;
      const T *const ppixel = &pixel;
      if (is_empty() || ppixel<_data || ppixel>=_data+siz) return false;
      unsigned int off = (unsigned int)(ppixel - _data);
      const unsigned int nc = off/whd;
      off%=whd;
      const unsigned int nz = off/wh;
      off%=wh;
      const unsigned int ny = off/_width, nx = off%_width;
      x = (t)nx; y = (t)ny; z = (t)nz; c = (t)nc;
      return true;
    }

    //! Test if pixel value is inside image bounds and get its X,Y and Z-coordinates.
    /**
       Similar to contains(const T&,t&,t&,t&,t&) const, except that only the X,Y and Z-coordinates are set.
    **/
    template<typename t>
    bool contains(const T& pixel, t& x, t& y, t& z) const {
      const unsigned int wh = _width*_height, whd = wh*_depth, siz = whd*_spectrum;
      const T *const ppixel = &pixel;
      if (is_empty() || ppixel<_data || ppixel>=_data+siz) return false;
      unsigned int off = ((unsigned int)(ppixel - _data))%whd;
      const unsigned int nz = off/wh;
      off%=wh;
      const unsigned int ny = off/_width, nx = off%_width;
      x = (t)nx; y = (t)ny; z = (t)nz;
      return true;
    }

    //! Test if pixel value is inside image bounds and get its X and Y-coordinates.
    /**
       Similar to contains(const T&,t&,t&,t&,t&) const, except that only the X and Y-coordinates are set.
    **/
    template<typename t>
    bool contains(const T& pixel, t& x, t& y) const {
      const unsigned int wh = _width*_height, siz = wh*_depth*_spectrum;
      const T *const ppixel = &pixel;
      if (is_empty() || ppixel<_data || ppixel>=_data+siz) return false;
      unsigned int off = ((unsigned int)(ppixel - _data))%wh;
      const unsigned int ny = off/_width, nx = off%_width;
      x = (t)nx; y = (t)ny;
      return true;
    }

    //! Test if pixel value is inside image bounds and get its X-coordinate.
    /**
       Similar to contains(const T&,t&,t&,t&,t&) const, except that only the X-coordinate is set.
    **/
    template<typename t>
    bool contains(const T& pixel, t& x) const {
      const T *const ppixel = &pixel;
      if (is_empty() || ppixel<_data || ppixel>=_data+size()) return false;
      x = (t)(((unsigned int)(ppixel - _data))%_width);
      return true;
    }

    //! Test if pixel value is inside image bounds.
    /**
       Similar to contains(const T&,t&,t&,t&,t&) const, except that no pixel coordinates are set.
    **/
    bool contains(const T& pixel) const {
      const T *const ppixel = &pixel;
      return !is_empty() && ppixel>=_data && ppixel<_data + size();
    }

    //! Test if pixel buffers of instance and input images overlap.
    /**
       Return \c true, if pixel buffers attached to image instance and input image \c img overlap, and \c false otherwise.
       \param img : Input image to compare with.
       \note
       - Buffer overlapping may happen when manipulating \e shared images.
       - If two image buffers overlap, operating on one of the image will probably modify the other one.
       - Most of the time, \c CImg<T> instances are \e non-shared and do not overlap between each others.
       \par Sample code :
       \code
       const CImg<float>
         img1("reference.jpg"),             // Load RGB-color image.
         img2 = img1.get_shared_channel(1); // Get shared version of the green channel.
       if (img1.is_overlapped(img2)) {      // Test succeeds, 'img1' and 'img2' overlaps.
         std::printf("Buffers overlap !\n");
       }
       \endcode
       \sa is_shared().
    **/
    template<typename t>
    bool is_overlapped(const CImg<t>& img) const {
      const unsigned int csiz = size(), isiz = img.size();
      return !((void*)(_data + csiz)<=(void*)img._data || (void*)_data>=(void*)(img._data + isiz));
    }

    //! Test if the set {\c *this,\c primitives,\c colors,\c opacities} defines a valid 3d object.
    /**
       Return \c true is the 3d object represented by the set {\c *this,\c primitives,\c colors,\c opacities} defines a
       valid 3d object, and \c false otherwise. The vertex coordinates are defined by the instance image.
       \param primitives : List of primitives of the 3d object.
       \param colors : List of colors of the 3d object.
       \param opacities : List (or image) of opacities of the 3d object.
       \param is_full_check : Boolean telling if full checking of the 3d object must be performed.
       \param[out] error_message : C-string to contain the error message, if the test does not succeed.
       \note
       - Set \c is_full_checking to \c false to speed-up the 3d object checking. In this case, only the size of
         each 3d object component is checked.
       - Size of the string \c error_message should be at least 128-bytes long, to be able to contain the error message.
       \sa is_CImg3d(),
           draw_object3d(),
           display_object3d().
    **/
    template<typename tp, typename tc, typename to>
    bool is_object3d(const CImgList<tp>& primitives,
                     const CImgList<tc>& colors,
                     const to& opacities,
                     const bool is_full_check=true,
                     char *const error_message=0) const {
      if (error_message) *error_message = 0;

      // Check consistency for the particular case of an empty 3d object.
      if (is_empty()) {
        if (primitives || colors || opacities) {
          if (error_message) std::sprintf(error_message,
                                          "3d object has no vertices but %u primitives, %u colors and %u opacities",
                                          primitives._width,colors._width,opacities.size());
          return false;
        }
        return true;
      }

      // Check consistency of vertices.
      if (_height!=3 || _depth>1 || _spectrum>1) { // Check vertices dimensions.
        if (error_message) std::sprintf(error_message,
                                        "3d object (%u,%u) has invalid vertices dimensions (%u,%u,%u,%u)",
                                        _width,primitives._width,_width,_height,_depth,_spectrum);
        return false;
      }
      if (colors._width>primitives._width+1) {
        if (error_message) std::sprintf(error_message,
                                        "3d object (%u,%u) defines %u colors",
                                        _width,primitives._width,colors._width);
        return false;
      }
      if (opacities.size()>primitives._width) {
        if (error_message) std::sprintf(error_message,
                                        "3d object (%u,%u) defines %u opacities",
                                        _width,primitives._width,opacities.size());
        return false;
      }
      if (!is_full_check) return true;

      // Check consistency of primitives.
      cimglist_for(primitives,l) {
        const CImg<tp>& primitive = primitives[l];
        const unsigned int psiz = primitive.size();
        switch (psiz) {
        case 1 : { // Point.
          const unsigned int i0 = (unsigned int)primitive(0);
          if (i0>=_width) {
            if (error_message) std::sprintf(error_message,
                                            "3d object (%u,%u) refers to invalid vertex indice %u in point primitive %u",
                                            _width,primitives._width,i0,l);
            return false;
          }
        } break;
        case 5 : { // Sphere.
          const unsigned int
            i0 = (unsigned int)primitive(0),
            i1 = (unsigned int)primitive(1);
          if (i0>=_width || i1>=_width) {
            if (error_message) std::sprintf(error_message,
                                            "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in sphere primitive %u",
                                            _width,primitives._width,i0,i1,l);
            return false;
          }
        } break;
        case 2 : // Segment.
        case 6 : {
          const unsigned int
            i0 = (unsigned int)primitive(0),
            i1 = (unsigned int)primitive(1);
          if (i0>=_width || i1>=_width) {
            if (error_message) std::sprintf(error_message,
                                            "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in segment primitive %u",
                                            _width,primitives._width,i0,i1,l);
            return false;
          }
        } break;
        case 3 : // Triangle.
        case 9 : {
          const unsigned int
            i0 = (unsigned int)primitive(0),
            i1 = (unsigned int)primitive(1),
            i2 = (unsigned int)primitive(2);
          if (i0>=_width || i1>=_width || i2>=_width) {
            if (error_message) std::sprintf(error_message,
                                            "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u) in triangle primitive %u",
                                            _width,primitives._width,i0,i1,i2,l);
            return false;
          }
        } break;
        case 4 : // Quadrangle.
        case 12 : {
          const unsigned int
            i0 = (unsigned int)primitive(0),
            i1 = (unsigned int)primitive(1),
            i2 = (unsigned int)primitive(2),
            i3 = (unsigned int)primitive(3);
          if (i0>=_width || i1>=_width || i2>=_width || i3>=_width) {
            if (error_message) std::sprintf(error_message,
                                            "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in quadrangle primitive %u",
                                            _width,primitives._width,i0,i1,i2,i3,l);
            return false;
          }
        } break;
        default :
          if (error_message) std::sprintf(error_message,
                                          "3d object has invalid primitive %u of size %u",
                                          l,psiz);
          return false;
        }
      }

      // Check consistency of colors.
      cimglist_for(colors,c) {
        const CImg<tc>& color = colors[c];
        if (!color) {
          if (error_message) std::sprintf(error_message,
                                          "3d object has empty color for primitive %u",
                                          c);
          return false;
        }
      }

      // Check consistency of light texture.
      if (colors._width>primitives._width) {
        const CImg<tc> &light = colors.back();
        if (!light || light._depth>1) {
          if (error_message) std::sprintf(error_message,
                                          "3d object has invalid light texture (%u,%u,%u,%u)",
                                          light._width,light._height,light._depth,light._spectrum);
          return false;
        }
      }

      return true;
    }

    //! Test if image instance represents a valid serialization of a 3d object.
    /**
       Return \c true if the image instance represents a valid serialization of a 3d object, and \c false otherwise.
       \param is_full_check : Boolean telling if full checking of the instance must be performed.
       \param[out] error_message : C-string to contain the error message, if the test does not succeed.
       \note
       - Set \c is_full_checking to \c false to speed-up the 3d object checking. In this case, only the size of
         each 3d object component is checked.
       - Size of the string \c error_message should be at least 128-bytes long, to be able to contain the error message.
       \sa is_object3d(),
           object3dtoCImg3d(const CImgList<tp>&,const CImgList<tc>&,const to&),
           draw_object3d(),
           display_object3d().
    **/
    bool is_CImg3d(const bool is_full_check=true, char *const error_message=0) const {
      if (error_message) *error_message = 0;

      // Check instance dimension and header.
      if (_width!=1 || _height<8 || _depth!=1 || _spectrum!=1) {
        if (error_message) std::sprintf(error_message,
                                        "CImg3d has invalid dimensions (%u,%u,%u,%u)",
                                        _width,_height,_depth,_spectrum);
        return false;
      }
      const T *ptrs = _data, *const ptre = end();
      if (!_is_CImg3d(*(ptrs++),'C') || !_is_CImg3d(*(ptrs++),'I') || !_is_CImg3d(*(ptrs++),'m') ||
          !_is_CImg3d(*(ptrs++),'g') || !_is_CImg3d(*(ptrs++),'3') || !_is_CImg3d(*(ptrs++),'d')) {
        if (error_message) std::sprintf(error_message,
                                        "CImg3d header not found");
        return false;
      }
      const unsigned int
        nb_points = cimg::float2uint((float)*(ptrs++)),
        nb_primitives = cimg::float2uint((float)*(ptrs++));

      // Check consistency of vertex data.
      if (!nb_points) {
        if (nb_primitives) {
          if (error_message) std::sprintf(error_message,
                                          "CImg3d has no vertices but %u primitives",
                                          nb_primitives);
          return false;
        }
        if (ptrs!=ptre) {
          if (error_message) std::sprintf(error_message,
                                          "CImg3d (%u,%u) is empty but contains %u byte%s more than expected",
                                          nb_points,nb_primitives,(unsigned int)(ptre-ptrs),(ptre-ptrs)>1?"s":"");
          return false;
        }
        return true;
      }
      ptrs+=3*nb_points;
      if (ptrs>ptre) {
        if (error_message) std::sprintf(error_message,
                                        "CImg3d (%u,%u) has incomplete vertex data",
                                        nb_points,nb_primitives);
        return false;
      }
      if (!is_full_check) return true;

      // Check consistency of primitive data.
      if (ptrs==ptre) {
        if (error_message) std::sprintf(error_message,
                                        "CImg3d (%u,%u) has no primitive data",
                                        nb_points,nb_primitives);
        return false;
      }
      for (unsigned int p = 0; p<nb_primitives; ++p) {
        const unsigned int nb_inds = (unsigned int)*(ptrs++);
        switch (nb_inds) {
        case 1 : { // Point.
          const unsigned int i0 = cimg::float2uint((float)*(ptrs++));
          if (i0>=nb_points) {
            if (error_message) std::sprintf(error_message,
                                            "CImg3d (%u,%u) refers to invalid vertex indice %u in point primitive %u",
                                            nb_points,nb_primitives,i0,p);
            return false;
          }
        } break;
        case 5 : { // Sphere.
          const unsigned int
            i0 = cimg::float2uint((float)*(ptrs++)),
            i1 = cimg::float2uint((float)*(ptrs++));
          ptrs+=3;
          if (i0>=nb_points || i1>=nb_points) {
            if (error_message) std::sprintf(error_message,
                                            "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in sphere primitive %u",
                                            nb_points,nb_primitives,i0,i1,p);
            return false;
          }
        } break;
        case 2 : case 6 : { // Segment.
          const unsigned int
            i0 = cimg::float2uint((float)*(ptrs++)),
            i1 = cimg::float2uint((float)*(ptrs++));
          if (nb_inds==6) ptrs+=4;
          if (i0>=nb_points || i1>=nb_points) {
            if (error_message) std::sprintf(error_message,
                                            "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in segment primitive %u",
                                            nb_points,nb_primitives,i0,i1,p);
            return false;
          }
        } break;
        case 3 : case 9 : { // Triangle.
          const unsigned int
            i0 = cimg::float2uint((float)*(ptrs++)),
            i1 = cimg::float2uint((float)*(ptrs++)),
            i2 = cimg::float2uint((float)*(ptrs++));
          if (nb_inds==9) ptrs+=6;
          if (i0>=nb_points || i1>=nb_points || i2>=nb_points) {
            if (error_message) std::sprintf(error_message,
                                            "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u) in triangle primitive %u",
                                            nb_points,nb_primitives,i0,i1,i2,p);
            return false;
          }
        } break;
        case 4 : case 12 : { // Quadrangle.
          const unsigned int
            i0 = cimg::float2uint((float)*(ptrs++)),
            i1 = cimg::float2uint((float)*(ptrs++)),
            i2 = cimg::float2uint((float)*(ptrs++)),
            i3 = cimg::float2uint((float)*(ptrs++));
          if (nb_inds==12) ptrs+=8;
          if (i0>=nb_points || i1>=nb_points || i2>=nb_points || i3>=nb_points) {
            if (error_message) std::sprintf(error_message,
                                            "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in quadrangle primitive %u",
                                            nb_points,nb_primitives,i0,i1,i2,i3,p);
            return false;
          }
        } break;
        default :
          if (error_message) std::sprintf(error_message,
                                          "CImg3d (%u,%u) has invalid primitive %u of size %u",
                                          nb_points,nb_primitives,p,nb_inds);
          return false;
        }
        if (ptrs>ptre) {
          if (error_message) std::sprintf(error_message,
                                          "CImg3d (%u,%u) has incomplete primitive data for primitive %u",
                                          nb_points,nb_primitives,p);
          return false;
        }
      }

      // Check consistency of color data.
      if (ptrs==ptre) {
        if (error_message) std::sprintf(error_message,
                                        "CImg3d (%u,%u) has no color/texture data",
                                        nb_points,nb_primitives);
        return false;
      }
      for (unsigned int c = 0; c<nb_primitives; ++c) {
        if ((int)*(ptrs++)!=-128) ptrs+=2;
        else if ((ptrs+=3)<ptre) {
          const unsigned int w = (unsigned int)*(ptrs-3), h = (unsigned int)*(ptrs-2), s = (unsigned int)*(ptrs-1);
          if (!h && !s) {
            if (w>=c) {
              if (error_message) std::sprintf(error_message,
                                              "CImg3d (%u,%u) refers to invalid shared sprite/texture indice %u for primitive %u",
                                              nb_points,nb_primitives,w,c);
              return false;
            }
          } else ptrs+=w*h*s;
        }
        if (ptrs>ptre) {
          if (error_message) std::sprintf(error_message,
                                          "CImg3d (%u,%u) has incomplete color/texture data for primitive %u",
                                          nb_points,nb_primitives,c);
          return false;
        }
      }

      // Check consistency of opacity data.
      if (ptrs==ptre) {
        if (error_message) std::sprintf(error_message,
                                        "CImg3d (%u,%u) has no opacity data",
                                        nb_points,nb_primitives);
        return false;
      }
      for (unsigned int o = 0; o<nb_primitives; ++o) {
        if ((int)*(ptrs++)==-128 && (ptrs+=3)<ptre) {
          const unsigned int w = (unsigned int)*(ptrs-3), h = (unsigned int)*(ptrs-2), s = (unsigned int)*(ptrs-1);
          if (!h && !s) {
            if (w>=o) {
              if (error_message) std::sprintf(error_message,
                                              "CImg3d (%u,%u) refers to invalid shared opacity indice %u for primitive %u",
                                              nb_points,nb_primitives,w,o);
              return false;
            }
          } else ptrs+=w*h*s;
        }
        if (ptrs>ptre) {
          if (error_message) std::sprintf(error_message,
                                          "CImg3d (%u,%u) has incomplete opacity data for primitive %u",
                                          nb_points,nb_primitives,o);
          return false;
        }
      }

      // Check end of data.
      if (ptrs<ptre) {
        if (error_message) std::sprintf(error_message,
                                        "CImg3d (%u,%u) contains %u byte%s more than expected",
                                        nb_points,nb_primitives,(unsigned int)(ptre-ptrs),(ptre-ptrs)>1?"s":"");
        return false;
      }
      return true;
    }

    static bool _is_CImg3d(const T val, const char c) {
      return val>=(T)c && val<(T)(c+1);
    }

    //@}
    //-------------------------------------
    //
    //! \name Mathematical Functions
    //@{
    //-------------------------------------

    // Define the math formula parser/compiler and evaluator.
    struct _cimg_math_parser {
      CImgList<charT> label;
      CImgList<uintT> code;
      CImg<uintT> level, opcode;
      CImg<doubleT> mem;
      CImg<charT> expr;
      const CImg<T>& reference;
      CImg<Tdouble> reference_stats;
      unsigned int mempos, result;
      const char *const calling_function;
#define _cimg_mp_return(x) { *se = saved_char; return x; }
#define _cimg_mp_opcode0(op) _cimg_mp_return(opcode0(op));
#define _cimg_mp_opcode1(op,i1) _cimg_mp_return(opcode1(op,i1));
#define _cimg_mp_opcode2(op,i1,i2) { const unsigned int _i1 = i1, _i2 = i2; _cimg_mp_return(opcode2(op,_i1,_i2)); }
#define _cimg_mp_opcode3(op,i1,i2,i3) { const unsigned int _i1 = i1, _i2 = i2, _i3 = i3; _cimg_mp_return(opcode3(op,_i1,_i2,_i3)); }
#define _cimg_mp_opcode5(op,i1,i2,i3,i4,i5) { const unsigned int _i1 = i1, _i2 = i2, _i3 = i3, _i4 = i4, _i5 = i5; \
          _cimg_mp_return(opcode5(op,_i1,_i2,_i3,_i4,_i5)); }

      // Constructor - Destructor.
      _cimg_math_parser(const CImg<T>& img, const char *const expression, const char *const funcname=0):
        reference(img),calling_function(funcname?funcname:"cimg_math_parser") {
        unsigned int l = 0;
        if (expression) {
          l = std::strlen(expression);
          expr.assign(expression,l+1);
          if (*expr._data) {
            char *d = expr._data;
            for (const char *s = expr._data; *s || (bool)(*d=0); ++s) if (*s!=' ') *(d++) = *s;
            l = d - expr._data;
          }
        }
        if (!l) throw CImgArgumentException("[_cimg_math_parser] "
                                            "CImg<%s>::%s() : Empty specified expression.",
                                            pixel_type(),calling_function);

        int lv = 0; // Count parenthesis level of expression.
        level.assign(l);
        unsigned int *pd = level._data;
        for (const char *ps = expr._data; *ps && lv>=0; ++ps) *(pd++) = (unsigned int)(*ps=='('?lv++:*ps==')'?--lv:lv);
        if (lv!=0) {
          throw CImgArgumentException("[_cimg_math_parser] "
                                      "CImg<%s>::%s() : Unbalanced parentheses in specified expression '%s'.",
                                      pixel_type(),calling_function,
                                      expr._data);
        }
        // Init constant values.
        mem.assign(512);
        label.assign(512);
        mem[0] = 0;
        mem[1] = 1;
        mem[2] = (double)reference._width;
        mem[3] = (double)reference._height;
        mem[4] = (double)reference._depth;
        mem[5] = (double)reference._spectrum;
        mem[6] = cimg::PI;
        mem[7] = std::exp(1.0); // Then [8] = x, [9] = y, [10] = z, [11] = c
        mempos = 12;
        result = compile(expr._data,expr._data+l); // Compile formula into a serie of opcodes.
      }

      // Insert code instructions.
      unsigned int opcode0(const char op) {
        if (mempos>=mem._width) mem.resize(-200,1,1,1,0);
        const unsigned int pos = mempos++;
        CImg<uintT>::vector(op,pos).move_to(code);
        return pos;
      }

      unsigned int opcode1(const char op, const unsigned int arg1) {
        if (mempos>=mem._width) mem.resize(-200,1,1,1,0);
        const unsigned int pos = mempos++;
        CImg<uintT>::vector(op,pos,arg1).move_to(code);
        return pos;
      }

      unsigned int opcode2(const char op, const unsigned int arg1, const unsigned int arg2) {
        if (mempos>=mem._width) mem.resize(-200,1,1,1,0);
        const unsigned int pos = mempos++;
        CImg<uintT>::vector(op,pos,arg1,arg2).move_to(code);
        return pos;
      }

      unsigned int opcode3(const char op, const unsigned int arg1, const unsigned int arg2, const unsigned int arg3) {
        if (mempos>=mem._width) mem.resize(-200,1,1,1,0);
        const unsigned int pos = mempos++;
        CImg<uintT>::vector(op,pos,arg1,arg2,arg3).move_to(code);
        return pos;
      }

      unsigned int opcode5(const char op, const unsigned int arg1, const unsigned int arg2, const unsigned int arg3,
                           const unsigned int arg4, const unsigned int arg5) {
        if (mempos>=mem._width) mem.resize(-200,1,1,1,0);
        const unsigned int pos = mempos++;
        CImg<uintT>::vector(op,pos,arg1,arg2,arg3,arg4,arg5).move_to(code);
        return pos;
      }

      // Compilation procedure.
      unsigned int compile(char *const ss, char *const se) {
        if (!ss || se<=ss || !*ss) {
          throw CImgArgumentException("[_cimg_math_parser] "
                                      "CImg<%s>::%s() : Missing item in specified expression '%s'.",
                                      pixel_type(),calling_function,
                                      expr._data);
        }
        char
          *const se1 = se-1, *const se2 = se-2, *const se3 = se-3, *const se4 = se-4,
          *const ss1 = ss+1, *const ss2 = ss+2, *const ss3 = ss+3, *const ss4 = ss+4,
          *const ss5 = ss+5, *const ss6 = ss+6, *const ss7 = ss+7;
        const char saved_char = *se; *se = 0;
        const unsigned int clevel = level[ss-expr._data], clevel1 = clevel+1;
        if (*se1==';') return compile(ss,se1);

        // Look for a single value, variable or variable assignment.
        char end = 0, sep = 0; double val = 0;
        const int nb = std::sscanf(ss,"%lf%c%c",&val,&sep,&end);
        if (nb==1) {
          if (val==0) _cimg_mp_return(0);
          if (val==1) _cimg_mp_return(1);
          if (mempos>=mem._width) mem.resize(-200,1,1,1,0);
          const unsigned int pos = mempos++;
          mem[pos] = val;
          _cimg_mp_return(pos);
        }
        if (nb==2 && sep=='%') {
          if (val==0) _cimg_mp_return(0);
          if (val==100) _cimg_mp_return(1);
          if (mempos>=mem._width) mem.resize(-200,1,1,1,0);
          const unsigned int pos = mempos++;
          mem[pos] = val/100;
          _cimg_mp_return(pos);
        }
        if (ss1==se) switch (*ss) {
          case 'w' : _cimg_mp_return(2); case 'h' : _cimg_mp_return(3); case 'd' : _cimg_mp_return(4); case 's' : _cimg_mp_return(5);
          case 'x' : _cimg_mp_return(8); case 'y' : _cimg_mp_return(9); case 'z' : _cimg_mp_return(10); case 'c' : _cimg_mp_return(11);
          case 'e' : _cimg_mp_return(7);
          case 'u' : case '?' : _cimg_mp_opcode2(0,0,1);
          case 'g' : _cimg_mp_opcode0(1);
          case 'i' : _cimg_mp_opcode0(2);
          }
        if (ss1==se1) {
          if (*ss=='p' && *ss1=='i') _cimg_mp_return(6); // pi
          if (*ss=='i') {
            if (*ss1=='m') _cimg_mp_opcode0(57); // im
            if (*ss1=='M') _cimg_mp_opcode0(58); // iM
            if (*ss1=='a') _cimg_mp_opcode0(59); // ia
            if (*ss1=='v') _cimg_mp_opcode0(60); // iv
          }
          if (*ss1=='m') {
            if (*ss=='x') _cimg_mp_opcode0(61); // xm
            if (*ss=='y') _cimg_mp_opcode0(62); // ym
            if (*ss=='z') _cimg_mp_opcode0(63); // zm
            if (*ss=='c') _cimg_mp_opcode0(64); // cm
          }
          if (*ss1=='M') {
            if (*ss=='x') _cimg_mp_opcode0(65); // xM
            if (*ss=='y') _cimg_mp_opcode0(66); // yM
            if (*ss=='z') _cimg_mp_opcode0(67); // zM
            if (*ss=='c') _cimg_mp_opcode0(68); // cM
          }
        }
        if (ss3==se) {
          if (*ss=='x' && *ss1=='/' && *ss2=='w') _cimg_mp_opcode0(3);
          if (*ss=='y' && *ss1=='/' && *ss2=='h') _cimg_mp_opcode0(4);
          if (*ss=='z' && *ss1=='/' && *ss2=='d') _cimg_mp_opcode0(5);
          if (*ss=='c' && *ss1=='/' && *ss2=='s') _cimg_mp_opcode0(6);
        }

        // Look for variable declarations.
        for (char *s = se2; s>ss; --s) if (*s==';' && level[s-expr._data]==clevel) { compile(ss,s); _cimg_mp_return(compile(s+1,se)); }
        for (char *s = ss1, *ps = ss, *ns = ss2; s<se1; ++s, ++ps, ++ns)
          if (*s=='=' && *ns!='=' && *ps!='=' && *ps!='>' && *ps!='<' && *ps!='!' && level[s-expr._data]==clevel) {
             CImg<charT> variable_name(ss,s-ss+1); variable_name.back() = 0;
             bool is_valid_name = true;
             if ((*ss>='0' && *ss<='9') ||
                 (s==ss+1 && (*ss=='x' || *ss=='y' || *ss=='z' || *ss=='c' ||
                              *ss=='w' || *ss=='h' || *ss=='d' || *ss=='s' ||
                              *ss=='e' || *ss=='u' || *ss=='g' || *ss=='i')) ||
                 (s==ss+2 && ((*ss=='p' && *(ss+1)=='i') ||
                              (*ss=='i' && (*(ss+1)=='m' || *(ss+1)=='M' || *(ss+1)=='a' || *(ss+1)=='v'))))) is_valid_name = false;
             for (const char *ns = ss; ns<s; ++ns)
               if ((*ns<'a' || *ns>'z') && (*ns<'A' || *ns>'Z') && (*ns<'0' || *ns>'9') && *ns!='_') {
                 is_valid_name = false; break;
               }
             if (!is_valid_name) {
               *se = saved_char;
               if (!std::strcmp(variable_name,"x") || !std::strcmp(variable_name,"y") || !std::strcmp(variable_name,"z") ||
                   !std::strcmp(variable_name,"c") || !std::strcmp(variable_name,"w") || !std::strcmp(variable_name,"h") ||
                   !std::strcmp(variable_name,"d") || !std::strcmp(variable_name,"s") || !std::strcmp(variable_name,"e") ||
                   !std::strcmp(variable_name,"u") || !std::strcmp(variable_name,"g") || !std::strcmp(variable_name,"i") ||
                   !std::strcmp(variable_name,"pi") || !std::strcmp(variable_name,"im") || !std::strcmp(variable_name,"iM") ||
                   !std::strcmp(variable_name,"ia") || !std::strcmp(variable_name,"iv"))
                  throw CImgArgumentException("[_cimg_math_parser] "
                                             "CImg<%s>::%s() : Invalid assignment of reserved variable name '%s' in specified expression '%s'.",
                                             pixel_type(),calling_function,
                                             variable_name._data,expr._data);
               else
                 throw CImgArgumentException("[_cimg_math_parser] "
                                             "CImg<%s>::%s() : Invalid variable name '%s' in specified expression '%s'.",
                                             pixel_type(),calling_function,
                                             variable_name._data,expr._data);
             }
             for (unsigned int i = 0; i<mempos; ++i) // Check for existing variable with same name.
               if (label[i]._data && !std::strcmp(variable_name,label[i])) {
                 *se = saved_char;
                 throw CImgArgumentException("[_cimg_math_parser] "
                                             "CImg<%s>::%s() : Invalid multiple assignments of variable '%s' in specified expression '%s'.",
                                             pixel_type(),calling_function,
                                             variable_name._data,expr._data);
               }
             const unsigned int src_pos = compile(s+1,se);
             if (mempos>=mem.size()) mem.resize(-200,1,1,1,0);
             const unsigned int dest_pos = mempos++;
             variable_name.move_to(label[dest_pos]);
             CImg<uintT>::vector(7,dest_pos,src_pos).move_to(code);
             _cimg_mp_return(dest_pos);
           }

        // Look for unary/binary operators. The operator precedences is defined as in C++.
        for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='|' && *ns=='|' && level[s-expr._data]==clevel) _cimg_mp_opcode2(8,compile(ss,s),compile(s+2,se));
        for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='&' && *ns=='&' && level[s-expr._data]==clevel) _cimg_mp_opcode2(9,compile(ss,s),compile(s+2,se));
        for (char *s = se2; s>ss; --s) if (*s=='|' && level[s-expr._data]==clevel) _cimg_mp_opcode2(10,compile(ss,s),compile(s+1,se));
        for (char *s = se2; s>ss; --s) if (*s=='&' && level[s-expr._data]==clevel) _cimg_mp_opcode2(11,compile(ss,s),compile(s+1,se));
        for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='!' && *ns=='=' && level[s-expr._data]==clevel) _cimg_mp_opcode2(12,compile(ss,s),compile(s+2,se));
        for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='=' && *ns=='=' && level[s-expr._data]==clevel) _cimg_mp_opcode2(13,compile(ss,s),compile(s+2,se));
        for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='<' && *ns=='=' && level[s-expr._data]==clevel) _cimg_mp_opcode2(14,compile(ss,s),compile(s+2,se));
        for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='>' && *ns=='=' && level[s-expr._data]==clevel) _cimg_mp_opcode2(15,compile(ss,s),compile(s+2,se));
        for (char *s = se2, *ns = se1, *ps = se3; s>ss; --s, --ns, --ps)
          if (*s=='<' && *ns!='<' && *ps!='<' && level[s-expr._data]==clevel) _cimg_mp_opcode2(16,compile(ss,s),compile(s+1,se));
        for (char *s = se2, *ns = se1, *ps = se3; s>ss; --s, --ns, --ps)
          if (*s=='>' && *ns!='>' && *ps!='>' && level[s-expr._data]==clevel) _cimg_mp_opcode2(17,compile(ss,s),compile(s+1,se));
        for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='<' && *ns=='<' && level[s-expr._data]==clevel) _cimg_mp_opcode2(18,compile(ss,s),compile(s+2,se));
        for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='>' && *ns=='>' && level[s-expr._data]==clevel) _cimg_mp_opcode2(19,compile(ss,s),compile(s+2,se));
        for (char *s = se2, *ps = se3; s>ss; --s, --ps)
          if (*s=='+' && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' && *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' &&
              (*ps!='e' || !(ps>ss && (*(ps-1)=='.' || (*(ps-1)>='0' && *(ps-1)<='9')))) && level[s-expr._data]==clevel)
            _cimg_mp_opcode2(21,compile(ss,s),compile(s+1,se));
        for (char *s = se2, *ps = se3; s>ss; --s, --ps)
          if (*s=='-' && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' && *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' &&
              (*ps!='e' || !(ps>ss && (*(ps-1)=='.' || (*(ps-1)>='0' && *(ps-1)<='9')))) && level[s-expr._data]==clevel)
            _cimg_mp_opcode2(20,compile(ss,s),compile(s+1,se));
        for (char *s = se2; s>ss; --s) if (*s=='*' && level[s-expr._data]==clevel) _cimg_mp_opcode2(22,compile(ss,s),compile(s+1,se));
        for (char *s = se2; s>ss; --s) if (*s=='/' && level[s-expr._data]==clevel) _cimg_mp_opcode2(23,compile(ss,s),compile(s+1,se));
        for (char *s = se2, *ns = se1; s>ss; --s, --ns)
          if (*s=='%' && *ns!='^' && level[s-expr._data]==clevel)
            _cimg_mp_opcode2(24,compile(ss,s),compile(s+1,se));
        if (ss<se1) {
          if (*ss=='+') _cimg_mp_return(compile(ss1,se));
          if (*ss=='-') _cimg_mp_opcode1(26,compile(ss1,se));
          if (*ss=='!') _cimg_mp_opcode1(27,compile(ss1,se));
          if (*ss=='~') _cimg_mp_opcode1(28,compile(ss1,se));
        }
        for (char *s = se2; s>ss; --s) if (*s=='^' && level[s-expr._data]==clevel) _cimg_mp_opcode2(25,compile(ss,s),compile(s+1,se));

        // Look for a function call or a parenthesis.
        if (*se1==')') {
          if (*ss=='(') _cimg_mp_return(compile(ss1,se1));
          if (!std::strncmp(ss,"sin(",4)) _cimg_mp_opcode1(29,compile(ss4,se1));
          if (!std::strncmp(ss,"cos(",4)) _cimg_mp_opcode1(30,compile(ss4,se1));
          if (!std::strncmp(ss,"tan(",4)) _cimg_mp_opcode1(31,compile(ss4,se1));
          if (!std::strncmp(ss,"asin(",5)) _cimg_mp_opcode1(32,compile(ss5,se1));
          if (!std::strncmp(ss,"acos(",5)) _cimg_mp_opcode1(33,compile(ss5,se1));
          if (!std::strncmp(ss,"atan(",5)) _cimg_mp_opcode1(34,compile(ss5,se1));
          if (!std::strncmp(ss,"sinh(",5)) _cimg_mp_opcode1(35,compile(ss5,se1));
          if (!std::strncmp(ss,"cosh(",5)) _cimg_mp_opcode1(36,compile(ss5,se1));
          if (!std::strncmp(ss,"tanh(",5)) _cimg_mp_opcode1(37,compile(ss5,se1));
          if (!std::strncmp(ss,"log10(",6)) _cimg_mp_opcode1(38,compile(ss6,se1));
          if (!std::strncmp(ss,"log(",4)) _cimg_mp_opcode1(39,compile(ss4,se1));
          if (!std::strncmp(ss,"exp(",4)) _cimg_mp_opcode1(40,compile(ss4,se1));
          if (!std::strncmp(ss,"sqrt(",5)) _cimg_mp_opcode1(41,compile(ss5,se1));
          if (!std::strncmp(ss,"sign(",5)) _cimg_mp_opcode1(42,compile(ss5,se1));
          if (!std::strncmp(ss,"abs(",4)) _cimg_mp_opcode1(43,compile(ss4,se1));
          if (!std::strncmp(ss,"atan2(",6)) {
            char *s1 = ss6; while (s1<se2 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1;
            _cimg_mp_opcode2(44,compile(ss6,s1),compile(s1+1,se1));
          }
          if (!std::strncmp(ss,"if(",3)) {
            char *s1 = ss3; while (s1<se4 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1;
            char *s2 = s1+1; while (s2<se2 && (*s2!=',' || level[s2-expr._data]!=clevel1)) ++s2;
            _cimg_mp_opcode3(45,compile(ss3,s1),compile(s1+1,s2),compile(s2+1,se1));
          }
          if (!std::strncmp(ss,"round(",6)) {
            unsigned int value = 0, round = 1, direction = 0;
            char *s1 = ss6; while (s1<se2 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1;
            value = compile(ss6,s1==se2?++s1:s1);
            if (s1<se1) {
              char *s2 = s1+1; while (s2<se2 && (*s2!=',' || level[s2-expr._data]!=clevel1)) ++s2;
              round = compile(s1+1,s2==se2?++s2:s2);
              if (s2<se1) direction = compile(s2+1,se1);
            }
            _cimg_mp_opcode3(46,value,round,direction);
          }
          if (!std::strncmp(ss,"?(",2) || !std::strncmp(ss,"u(",2)) {
            if (*ss2==')') _cimg_mp_opcode2(0,0,1);
            char *s1 = ss2; while (s1<se1 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1;
            if (s1<se1) _cimg_mp_opcode2(0,compile(ss2,s1),compile(s1+1,se1));
            _cimg_mp_opcode2(0,0,compile(ss2,s1));
          }
          if (!std::strncmp(ss,"i(",2)) {
            if (*ss2==')') _cimg_mp_return(0);
            unsigned int indx = 8, indy = 9, indz = 10, indc = 11, borders = 0;
            if (ss2!=se1) {
              char *s1 = ss2; while (s1<se2 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1;
              indx = compile(ss2,s1==se2?++s1:s1);
              if (s1<se1) {
                char *s2 = s1+1; while (s2<se2 && (*s2!=',' || level[s2-expr._data]!=clevel1)) ++s2;
                indy = compile(s1+1,s2==se2?++s2:s2);
                if (s2<se1) {
                  char *s3 = s2+1; while (s3<se2 && (*s3!=',' || level[s3-expr._data]!=clevel1)) ++s3;
                  indz = compile(s2+1,s3==se2?++s3:s3);
                  if (s3<se1) {
                    char *s4 = s3+1; while (s4<se2 && (*s4!=',' || level[s4-expr._data]!=clevel1)) ++s4;
                    indc = compile(s3+1,s4==se2?++s4:s4);
                    if (s4<se1) borders = compile(s4+1,se1);
                  }
                }
              }
            }
            _cimg_mp_opcode5(47,indx,indy,indz,indc,borders);
          }
          if (!std::strncmp(ss,"min(",4) || !std::strncmp(ss,"max(",4)) {
            CImgList<uintT> opcode;
            if (mempos>=mem.size()) mem.resize(-200,1,1,1,0);
            const unsigned int pos = mempos++;
            CImg<uintT>::vector(ss[1]=='i'?48:49,pos).move_to(opcode);
            for (char *s = ss4; s<se; ++s) {
              char *ns = s; while (ns<se && (*ns!=',' || level[ns-expr._data]!=clevel1) && (*ns!=')' || level[ns-expr._data]!=clevel)) ++ns;
              CImg<uintT>::vector(compile(s,ns)).move_to(opcode);
              s = ns;
            }
            (opcode>'y').move_to(code);
            _cimg_mp_return(pos);
          }
          if (!std::strncmp(ss,"arg(",4)) {
            CImgList<uintT> opcode;
            if (mempos>=mem.size()) mem.resize(-200,1,1,1,0);
            const unsigned int pos = mempos++;
            CImg<uintT>::vector(69,pos).move_to(opcode);
            for (char *s = ss4; s<se; ++s) {
              char *ns = s; while (ns<se && (*ns!=',' || level[ns-expr._data]!=clevel1) && (*ns!=')' || level[ns-expr._data]!=clevel)) ++ns;
              CImg<uintT>::vector(compile(s,ns)).move_to(opcode);
              s = ns;
            }
            (opcode>'y').move_to(code);
            _cimg_mp_return(pos);
          }
          if (!std::strncmp(ss,"narg(",5)) {
            if (*ss5==')') _cimg_mp_return(0);
            unsigned int nb_args = 0;
            for (char *s = ss5; s<se; ++s) {
              char *ns = s; while (ns<se && (*ns!=',' || level[ns-expr._data]!=clevel1) && (*ns!=')' || level[ns-expr._data]!=clevel)) ++ns;
              ++nb_args; s = ns;
            }
            if (nb_args==0 || nb_args==1) _cimg_mp_return(nb_args);
            if (mempos>=mem.size()) mem.resize(-200,1,1,1,0);
            const unsigned int pos = mempos++;
            mem[pos] = nb_args;
            _cimg_mp_return(pos);
          }
          if (!std::strncmp(ss,"isval(",6)) {
            char sep = 0, end = 0; double val = 0;
            if (std::sscanf(ss6,"%lf%c%c",&val,&sep,&end)==2 && sep==')') _cimg_mp_return(1);
            _cimg_mp_return(0);
          }
          if (!std::strncmp(ss,"isnan(",6)) _cimg_mp_opcode1(50,compile(ss6,se1));
          if (!std::strncmp(ss,"isinf(",6)) _cimg_mp_opcode1(51,compile(ss6,se1));
          if (!std::strncmp(ss,"isint(",6)) _cimg_mp_opcode1(52,compile(ss6,se1));
          if (!std::strncmp(ss,"isbool(",7)) _cimg_mp_opcode1(53,compile(ss7,se1));
          if (!std::strncmp(ss,"rol(",4) || !std::strncmp(ss,"ror(",4)) {
            unsigned int value = 0, nb = 1;
            char *s1 = ss4; while (s1<se2 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1;
            value = compile(ss4,s1==se2?++s1:s1);
            if (s1<se1) {
              char *s2 = s1+1; while (s2<se2 && (*s2!=',' || level[s2-expr._data]!=clevel1)) ++s2;
              nb = compile(s1+1,se1);
            }
            _cimg_mp_opcode2(*ss2=='l'?54:55,value,nb);
          }

          if (!std::strncmp(ss,"sinc(",5)) _cimg_mp_opcode1(56,compile(ss5,se1));
          if (!std::strncmp(ss,"int(",4)) _cimg_mp_opcode1(70,compile(ss4,se1));
        }

        // No known item found, assuming this is an already initialized variable.
        CImg<charT> variable_name(ss,se-ss+1); variable_name.back() = 0;
        for (unsigned int i = 0; i<mempos; ++i) if (label[i]._data && !std::strcmp(variable_name,label[i])) _cimg_mp_return(i);
        *se = saved_char;
        throw CImgArgumentException("[_cimg_math_parser] "
                                    "CImg<%s>::%s() : Invalid item '%s' in specified expression '%s'.\n",
                                    pixel_type(),calling_function,
                                    variable_name._data,expr._data);
        return 0;
      }

      // Evaluation functions, known by the parser.
      double mp_u() {
        return mem[opcode(2)] + cimg::rand()*(mem[opcode(3)]-mem[opcode(2)]);
      }
      double mp_g() {
        return cimg::grand();
      }
      double mp_i() {
        return (double)reference.atXYZC((int)mem[8],(int)mem[9],(int)mem[10],(int)mem[11],0);
      }
      double mp_xw() {
        return mem[8]/reference.width();
      }
      double mp_yh() {
        return mem[9]/reference.height();
      }
      double mp_zd() {
        return mem[10]/reference.depth();
      }
      double mp_cs() {
        return mem[11]/reference.spectrum();
      }
      double mp_equal() {
        return mem[opcode[2]];
      }
      double mp_logical_and() {
        return (double)((bool)mem[opcode(2)] && (bool)mem[opcode(3)]);
      }
      double mp_logical_or() {
        return (double)((bool)mem[opcode(2)] || (bool)mem[opcode(3)]);
      }
      double mp_infeq() {
        return (double)(mem[opcode(2)]<=mem[opcode(3)]);
      }
      double mp_supeq() {
        return (double)(mem[opcode(2)]>=mem[opcode(3)]);
      }
      double mp_noteq() {
        return (double)(mem[opcode(2)]!=mem[opcode(3)]);
      }
      double mp_eqeq() {
        return (double)(mem[opcode(2)]==mem[opcode(3)]);
      }
      double mp_inf() {
        return (double)(mem[opcode(2)]<mem[opcode(3)]);
      }
      double mp_sup() {
        return (double)(mem[opcode(2)]>mem[opcode(3)]);
      }
      double mp_add() {
        return mem[opcode(2)] + mem[opcode(3)];
      }
      double mp_sub() {
        return mem[opcode(2)] - mem[opcode(3)];
      }
      double mp_mul() {
        return mem[opcode(2)] * mem[opcode(3)];
      }
      double mp_div() {
        return mem[opcode(2)] / mem[opcode(3)];
      }
      double mp_minus() {
        return -mem[opcode(2)];
      }
      double mp_not() {
        return !mem[opcode(2)];
      }
      double mp_logical_not() {
        return !mem[opcode(2)];
      }
      double mp_bitwise_not() {
        return ~(unsigned long)mem[opcode(2)];
      }
      double mp_modulo() {
        return cimg::mod(mem[opcode(2)],mem[opcode(3)]);
      }
      double mp_bitwise_and() {
        return ((unsigned long)mem[opcode(2)] & (unsigned long)mem[opcode(3)]);
      }
      double mp_bitwise_or() {
        return ((unsigned long)mem[opcode(2)] | (unsigned long)mem[opcode(3)]);
      }
      double mp_pow() {
        return std::pow(mem[opcode(2)],mem[opcode(3)]);
      }
      double mp_sin() {
        return std::sin(mem[opcode(2)]);
      }
      double mp_cos() {
        return std::cos(mem[opcode(2)]);
      }
      double mp_tan() {
        return std::tan(mem[opcode(2)]);
      }
      double mp_asin() {
        return std::asin(mem[opcode(2)]);
      }
      double mp_acos() {
        return std::acos(mem[opcode(2)]);
      }
      double mp_atan() {
        return std::atan(mem[opcode(2)]);
      }
      double mp_sinh() {
        return std::sinh(mem[opcode(2)]);
      }
      double mp_cosh() {
        return std::cosh(mem[opcode(2)]);
      }
      double mp_tanh() {
        return std::tanh(mem[opcode(2)]);
      }
      double mp_log10() {
        return std::log10(mem[opcode(2)]);
      }
      double mp_log() {
        return std::log(mem[opcode(2)]);
      }
      double mp_exp() {
        return std::exp(mem[opcode(2)]);
      }
      double mp_sqrt() {
        return std::sqrt(mem[opcode(2)]);
      }
      double mp_sign() {
        return cimg::sign(mem[opcode(2)]);
      }
      double mp_abs() {
        return cimg::abs(mem[opcode(2)]);
      }
      double mp_atan2() {
        return std::atan2(mem[opcode(2)],mem[opcode(3)]);
      }
      double mp_if() {
        return mem[opcode(2)]?mem[opcode(3)]:mem[opcode(4)];
      }
      double mp_round() {
        return cimg::round(mem[opcode(2)],mem[opcode(3)],(int)mem[opcode(4)]);
      }
      double mp_ixyzc() {
        const int b = (int)mem[opcode(6)];
        if (b==2) return (double)reference.atXYZC(cimg::mod((int)mem[opcode(2)],reference.width()),
                                                  cimg::mod((int)mem[opcode(3)],reference.height()),
                                                  cimg::mod((int)mem[opcode(4)],reference.depth()),
                                                  cimg::mod((int)mem[opcode(5)],reference.spectrum()));
        if (b==1) return (double)reference.atXYZC((int)mem[opcode(2)],
                                                  (int)mem[opcode(3)],
                                                  (int)mem[opcode(4)],
                                                  (int)mem[opcode(5)]);
        return (double)reference.atXYZC((int)mem[opcode(2)],
                                        (int)mem[opcode(3)],
                                        (int)mem[opcode(4)],
                                        (int)mem[opcode(5)],0);
      }
      double mp_min() {
        double val = mem[opcode(2)];
        for (unsigned int i = 3; i<opcode._height; ++i) val = cimg::min(val,mem[opcode(i)]);
        return val;
      }
      double mp_max() {
        double val = mem[opcode(2)];
        for (unsigned int i = 3; i<opcode._height; ++i) val = cimg::max(val,mem[opcode(i)]);
        return val;
      }
      double mp_isnan() {
        const double val = mem[opcode(2)];
        return !(val==val);
      }
      double mp_isinf() {
        const double val = mem[opcode(2)];
        return val==(val+1);
      }
      double mp_isint() {
        const double val = mem[opcode(2)];
        return (double)(int)val==val;
      }
      double mp_isbool() {
        const double val = mem[opcode(2)];
        return (val==0.0 || val==1.0);
      }
      double mp_rol() {
        return cimg::rol(mem[opcode(2)],(unsigned int)mem[opcode(3)]);
      }
      double mp_ror() {
        return cimg::ror(mem[opcode(2)],(unsigned int)mem[opcode(3)]);
      }
      double mp_lsl() {
        return (long)mem[opcode(2)]<<(unsigned int)mem[opcode(3)];
      }
      double mp_lsr() {
        return (long)mem[opcode(2)]>>(unsigned int)mem[opcode(3)];
      }
      double mp_sinc() {
        return cimg::sinc(mem[opcode(2)]);
      }
      double mp_im() {
        if (!reference_stats) reference.get_stats().move_to(reference_stats);
        return reference_stats?reference_stats[0]:0;
      }
      double mp_iM() {
        if (!reference_stats) reference.get_stats().move_to(reference_stats);
        return reference_stats?reference_stats[1]:0;
      }
      double mp_ia() {
        if (!reference_stats) reference.get_stats().move_to(reference_stats);
        return reference_stats?reference_stats[2]:0;
      }
      double mp_iv() {
        if (!reference_stats) reference.get_stats().move_to(reference_stats);
        return reference_stats?reference_stats[3]:0;
      }
      double mp_xm() {
        if (!reference_stats) reference.get_stats().move_to(reference_stats);
        return reference_stats?reference_stats[4]:0;
      }
      double mp_ym() {
        if (!reference_stats) reference.get_stats().move_to(reference_stats);
        return reference_stats?reference_stats[5]:0;
      }
      double mp_zm() {
        if (!reference_stats) reference.get_stats().move_to(reference_stats);
        return reference_stats?reference_stats[6]:0;
      }
      double mp_cm() {
        if (!reference_stats) reference.get_stats().move_to(reference_stats);
        return reference_stats?reference_stats[7]:0;
      }
      double mp_xM() {
        if (!reference_stats) reference.get_stats().move_to(reference_stats);
        return reference_stats?reference_stats[8]:0;
      }
      double mp_yM() {
        if (!reference_stats) reference.get_stats().move_to(reference_stats);
        return reference_stats?reference_stats[9]:0;
      }
      double mp_zM() {
        if (!reference_stats) reference.get_stats().move_to(reference_stats);
        return reference_stats?reference_stats[10]:0;
      }
      double mp_cM() {
        if (!reference_stats) reference.get_stats().move_to(reference_stats);
        return reference_stats?reference_stats[11]:0;
      }
      double mp_arg() {
        const int _ind = (int)mem[opcode(2)];
        const unsigned int nb_args = opcode._height-2, ind = _ind<0?_ind+nb_args:(unsigned int)_ind;
        if (ind>=nb_args) return 0;
        return mem[opcode(ind+2)];
      }
      double mp_int() {
        return (double)(long)mem[opcode(2)];
      }

      // Evaluation procedure, with image data.
      double eval(const double x, const double y, const double z, const double c) {
        typedef double (_cimg_math_parser::*mp_func)();
        const mp_func mp_funcs[] = {
          &_cimg_math_parser::mp_u,            // 0
          &_cimg_math_parser::mp_g,            // 1
          &_cimg_math_parser::mp_i,            // 2
          &_cimg_math_parser::mp_xw,           // 3
          &_cimg_math_parser::mp_yh,           // 4
          &_cimg_math_parser::mp_zd,           // 5
          &_cimg_math_parser::mp_cs,           // 6
          &_cimg_math_parser::mp_equal,        // 7
          &_cimg_math_parser::mp_logical_or,   // 8
          &_cimg_math_parser::mp_logical_and,  // 9
          &_cimg_math_parser::mp_bitwise_or,   // 10
          &_cimg_math_parser::mp_bitwise_and,  // 11
          &_cimg_math_parser::mp_noteq,        // 12
          &_cimg_math_parser::mp_eqeq,         // 13
          &_cimg_math_parser::mp_infeq,        // 14
          &_cimg_math_parser::mp_supeq,        // 15
          &_cimg_math_parser::mp_inf,          // 16
          &_cimg_math_parser::mp_sup,          // 17
          &_cimg_math_parser::mp_lsl,          // 18
          &_cimg_math_parser::mp_lsr,          // 19
          &_cimg_math_parser::mp_sub,          // 20
          &_cimg_math_parser::mp_add,          // 21
          &_cimg_math_parser::mp_mul,          // 22
          &_cimg_math_parser::mp_div,          // 23
          &_cimg_math_parser::mp_modulo,       // 24
          &_cimg_math_parser::mp_pow,          // 25
          &_cimg_math_parser::mp_minus,        // 26
          &_cimg_math_parser::mp_logical_not,  // 27
          &_cimg_math_parser::mp_bitwise_not,  // 28
          &_cimg_math_parser::mp_sin,          // 29
          &_cimg_math_parser::mp_cos,          // 30
          &_cimg_math_parser::mp_tan,          // 31
          &_cimg_math_parser::mp_asin,         // 32
          &_cimg_math_parser::mp_acos,         // 33
          &_cimg_math_parser::mp_atan,         // 34
          &_cimg_math_parser::mp_sinh,         // 35
          &_cimg_math_parser::mp_cosh,         // 36
          &_cimg_math_parser::mp_tanh,         // 37
          &_cimg_math_parser::mp_log10,        // 38
          &_cimg_math_parser::mp_log,          // 39
          &_cimg_math_parser::mp_exp,          // 40
          &_cimg_math_parser::mp_sqrt,         // 41
          &_cimg_math_parser::mp_sign,         // 42
          &_cimg_math_parser::mp_abs,          // 43
          &_cimg_math_parser::mp_atan2,        // 44
          &_cimg_math_parser::mp_if,           // 45
          &_cimg_math_parser::mp_round,        // 46
          &_cimg_math_parser::mp_ixyzc,        // 47
          &_cimg_math_parser::mp_min,          // 48
          &_cimg_math_parser::mp_max,          // 49
          &_cimg_math_parser::mp_isnan,        // 50
          &_cimg_math_parser::mp_isinf,        // 51
          &_cimg_math_parser::mp_isint,        // 52
          &_cimg_math_parser::mp_isbool,       // 53
          &_cimg_math_parser::mp_rol,          // 54
          &_cimg_math_parser::mp_ror,          // 55
          &_cimg_math_parser::mp_sinc,         // 56
          &_cimg_math_parser::mp_im,           // 57
          &_cimg_math_parser::mp_iM,           // 58
          &_cimg_math_parser::mp_ia,           // 59
          &_cimg_math_parser::mp_iv,           // 60
          &_cimg_math_parser::mp_xm,           // 61
          &_cimg_math_parser::mp_ym,           // 62
          &_cimg_math_parser::mp_zm,           // 63
          &_cimg_math_parser::mp_cm,           // 64
          &_cimg_math_parser::mp_xM,           // 65
          &_cimg_math_parser::mp_yM,           // 66
          &_cimg_math_parser::mp_zM,           // 67
          &_cimg_math_parser::mp_cM,           // 68
          &_cimg_math_parser::mp_arg,          // 69
          &_cimg_math_parser::mp_int           // 70
        };

        if (!mem) return 0;
        mem[8] = x; mem[9] = y; mem[10] = z; mem[11] = c;
        opcode._is_shared = true; opcode._width = opcode._depth = opcode._spectrum = 1;
        cimglist_for(code,l) {
          const CImg<uintT> &op = code[l];
          opcode._data = op._data; opcode._height = op._height;  // Allows to avoid parameter passing to evaluation functions.
          mem[opcode(1)] = (this->*mp_funcs[opcode[0]])();
        }
        return mem[result];
      }
    };

    //! Compute the square value of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its square value \f$I_{(x,y,z,c)}^2\f$.
       \note
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \par Sample code :
       \code
       const CImg<float> img("reference.jpg");
       (img,img.get_sqr().normalize(0,255)).display();
       \endcode
       \image html ref_sqr.jpg
       \sa get_sqr() const,
           sqrt(),
           pow(),
           exp(),
           log(),
           log10().
    **/
    CImg<T>& sqr() {
      cimg_for(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(val*val); };
      return *this;
    }

    //! Compute the square value of each pixel value \newinstance.
    CImg<Tfloat> get_sqr() const {
      return CImg<Tfloat>(*this,false).sqr();
    }

    //! Compute the square root of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its square root \f$\sqrt{I_{(x,y,z,c)}}\f$.
       \note
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \par Sample code :
       \code
       const CImg<float> img("reference.jpg");
       (img,img.get_sqrt().normalize(0,255)).display();
       \endcode
       \image html ref_sqrt.jpg
       \sa get_sqrt() const,,
           sqr(),
           pow(),
           exp(),
           log(),
           log10().
    **/
    CImg<T>& sqrt() {
      cimg_for(*this,ptrd,T) *ptrd = (T)std::sqrt((double)*ptrd);
      return *this;
    }

    //! Compute the square root of each pixel value \newinstance.
    CImg<Tfloat> get_sqrt() const {
      return CImg<Tfloat>(*this,false).sqrt();
    }

    //! Compute the exponential of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its exponential \f$e^{I_{(x,y,z,c)}}\f$.
       \note
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \sa get_exp() const,
           sqr(),
           sqrt(),
           pow(),
           log(),
           log10().
    **/
    CImg<T>& exp() {
      cimg_for(*this,ptrd,T) *ptrd = (T)std::exp((double)*ptrd);
      return *this;
    }

    //! Compute the exponential of each pixel value \newinstance.
    CImg<Tfloat> get_exp() const {
      return CImg<Tfloat>(*this,false).exp();
    }

    //! Compute the logarithm of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its logarithm \f$log_e(I_{(x,y,z,c)})\f$.
       \note
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \sa get_log() const,
           sqr(),
           sqrt(),
           pow(),
           exp(),
           log10().
    **/
    CImg<T>& log() {
      cimg_for(*this,ptrd,T) *ptrd = (T)std::log((double)*ptrd);
      return *this;
    }

    //! Compute the logarithm of each pixel value \newinstance.
    CImg<Tfloat> get_log() const {
      return CImg<Tfloat>(*this,false).log();
    }

    //! Compute the base-10 logarithm of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its base-10 logarithm \f$log_{10}(I_{(x,y,z,c)})\f$.
       \note
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \sa get_log10(),
           sqr(),
           sqrt(),
           pow(),
           exp(),
           log().
    **/
    CImg<T>& log10() {
      cimg_for(*this,ptrd,T) *ptrd = (T)std::log10((double)*ptrd);
      return *this;
    }

    //! Compute the base-10 logarithm of each pixel value \newinstance.
    CImg<Tfloat> get_log10() const {
      return CImg<Tfloat>(*this,false).log10();
    }

    //! Compute the absolute value of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its absolute value \f$|I_{(x,y,z,c)}|\f$.
       \note
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \sa get_abs(),
           sign().
    **/
    CImg<T>& abs() {
      cimg_for(*this,ptrd,T) *ptrd = cimg::abs(*ptrd);
      return *this;
    }

    //! Compute the absolute value of each pixel value \newinstance.
    CImg<Tfloat> get_abs() const {
      return CImg<Tfloat>(*this,false).abs();
    }

    //! Compute the sign of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its sign \f$sign(I_{(x,y,z,c)})\f$.
       \note
       - The sign is set to :
         - \c 1 if pixel value is strictly positive.
         - \c -1 if pixel value is strictly negative.
         - \c 0 if pixel value is equal to \c 0.
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \sa get_sign(),
           abs().
    **/
    CImg<T>& sign() {
      cimg_for(*this,ptrd,T) *ptrd = cimg::sign(*ptrd);
      return *this;
    }

    //! Compute the sign of each pixel value \newinstance.
    CImg<Tfloat> get_sign() const {
      return CImg<Tfloat>(*this,false).sign();
    }

    //! Compute the cosine of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its cosine \f$cos(I_{(x,y,z,c)})\f$.
       \note
       - Pixel values are regarded as being in \e radian.
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \sa get_cos(),
           sin(),
           sinc(),
           tan().
    **/
    CImg<T>& cos() {
      cimg_for(*this,ptrd,T) *ptrd = (T)std::cos((double)*ptrd);
      return *this;
    }

    //! Compute the cosine of each pixel value \newinstance.
    CImg<Tfloat> get_cos() const {
      return CImg<Tfloat>(*this,false).cos();
    }

    //! Compute the sine of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its sine \f$sin(I_{(x,y,z,c)})\f$.
       \note
       - Pixel values are regarded as being in \e radian.
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \sa get_sin(),
           cos(),
           sinc(),
           tan().
    **/
    CImg<T>& sin() {
      cimg_for(*this,ptrd,T) *ptrd = (T)std::sin((double)*ptrd);
      return *this;
    }

    //! Compute the sine of each pixel value \newinstance.
    CImg<Tfloat> get_sin() const {
      return CImg<Tfloat>(*this,false).sin();
    }

    //! Compute the sinc of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its sinc \f$sinc(I_{(x,y,z,c)})\f$.
       \note
       - Pixel values are regarded as being exin \e radian.
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \sa get_sinc(),
           cos(),
           sin(),
           tan().
    **/
    CImg<T>& sinc() {
      cimg_for(*this,ptrd,T) *ptrd = (T)cimg::sinc((double)*ptrd);
      return *this;
    }

    //! Compute the sinc of each pixel value \newinstance.
    CImg<Tfloat> get_sinc() const {
      return CImg<Tfloat>(*this,false).sinc();
    }

    //! Compute the tangent of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its tangent \f$tan(I_{(x,y,z,c)})\f$.
       \note
       - Pixel values are regarded as being exin \e radian.
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \sa get_tan(),
           cos(),
           sin(),
           sinc().
    **/
    CImg<T>& tan() {
      cimg_for(*this,ptrd,T) *ptrd = (T)std::tan((double)*ptrd);
      return *this;
    }

    //! Compute the tangent of each pixel value \newinstance.
    CImg<Tfloat> get_tan() const {
      return CImg<Tfloat>(*this,false).tan();
    }

    //! Compute the hyperbolic cosine of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its hyperbolic cosine \f$cosh(I_{(x,y,z,c)})\f$.
       \note
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \sa get_cosh(),
           sinh(),
           tanh().
    **/
    CImg<T>& cosh() {
      cimg_for(*this,ptrd,T) *ptrd = (T)std::cosh((double)*ptrd);
      return *this;
    }

    //! Compute the hyperbolic cosine of each pixel value \newinstance.
    CImg<Tfloat> get_cosh() const {
      return CImg<Tfloat>(*this,false).cosh();
    }

    //! Compute the hyperbolic sine of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its hyperbolic sine \f$sinh(I_{(x,y,z,c)})\f$.
       \note
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \sa get_sinh(),
           cosh(),
           tanh().
    **/
    CImg<T>& sinh() {
      cimg_for(*this,ptrd,T) *ptrd = (T)std::sinh((double)*ptrd);
      return *this;
    }

    //! Compute the hyperbolic sine of each pixel value \newinstance.
    CImg<Tfloat> get_sinh() const {
      return CImg<Tfloat>(*this,false).sinh();
    }

    //! Compute the hyperbolic tangent of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its hyperbolic tangent \f$tanh(I_{(x,y,z,c)})\f$.
       \note
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \sa get_tanh(),
           cosh(),
           sinh().
    **/
    CImg<T>& tanh() {
      cimg_for(*this,ptrd,T) *ptrd = (T)std::tanh((double)*ptrd);
      return *this;
    }

    //! Compute the hyperbolic tangent of each pixel value \newinstance.
    CImg<Tfloat> get_tanh() const {
      return CImg<Tfloat>(*this,false).tanh();
    }

    //! Compute the arccosine of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its arccosine \f$acos(I_{(x,y,z,c)})\f$.
       \note
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \sa get_acos(),
           asin(),
           atan().
    **/
    CImg<T>& acos() {
      cimg_for(*this,ptrd,T) *ptrd = (T)std::acos((double)*ptrd);
      return *this;
    }

    //! Compute the arccosine of each pixel value \newinstance.
    CImg<Tfloat> get_acos() const {
      return CImg<Tfloat>(*this,false).acos();
    }

    //! Compute the arcsine of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its arcsine \f$asin(I_{(x,y,z,c)})\f$.
       \note
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \sa get_asin(),
           acos(),
           atan().
    **/
    CImg<T>& asin() {
      cimg_for(*this,ptrd,T) *ptrd = (T)std::asin((double)*ptrd);
      return *this;
    }

    //! Compute the arcsine of each pixel value \newinstance.
    CImg<Tfloat> get_asin() const {
      return CImg<Tfloat>(*this,false).asin();
    }

    //! Compute the arctangent of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its arctangent \f$atan(I_{(x,y,z,c)})\f$.
       \note
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \sa get_atan(),
           acos(),
           asin().
    **/
    CImg<T>& atan() {
      cimg_for(*this,ptrd,T) *ptrd = (T)std::atan((double)*ptrd);
      return *this;
    }

    //! Compute the arctangent of each pixel value \newinstance.
    CImg<Tfloat> get_atan() const {
      return CImg<Tfloat>(*this,false).atan();
    }

    //! Compute the arctangent2 of each pixel value.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its arctangent2 \f$atan2(I_{(x,y,z,c)})\f$.
       \param img : The image whose pixel values specify the second argument of the \c atan2() function.
       \note
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \par Sample code :
       \code
       const CImg<float>
          img_x(100,100,1,1,"x-w/2",false),   // Define an horizontal centered gradient, from '-width/2' to 'width/2'.
          img_y(100,100,1,1,"y-h/2",false),   // Define a vertical centered gradient, from '-height/2' to 'height/2'.
          img_atan2 = img_y.get_atan2(img_x); // Compute atan2(y,x) for each pixel value.
       (img_x,img_y,img_atan2).display();
       \endcode
       \image html ref_atan2.jpg
       \sa get_atan2(),
           atan().
    **/
    template<typename t>
    CImg<T>& atan2(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return atan2(+img);
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)std::atan2((double)*ptrd,(double)*(ptrs++));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)std::atan2((double)*ptrd,(double)*(ptrs++));
      }
      return *this;
    }

    //! Compute the arctangent2 of each pixel value \newinstance.
    template<typename t>
    CImg<Tfloat> get_atan2(const CImg<t>& img) const {
      return CImg<Tfloat>(*this,false).atan2(img);
    }

    //! In-place pointwise multiplication.
    /**
       Compute the pointwise multiplication between the image instance and the specified input image \c img.
       \param img : Input image, as the second operand of the multiplication.
       \note
       - Similar to operator+=(const CImg<t>&), except that it performs a pointwise multiplication instead of an addition.
       - It does \e not perform a \e matrix multiplication. For this purpose, use operator*=(const CImg<t>&) instead.
       \par Sample code :
       \code
       CImg<float>
         img("reference.jpg"),
         shade(img.width,img.height(),1,1,"-(x-w/2)^2-(y-h/2)^2",false);
       shade.normalize(0,1);
       (img,shade,img.get_mul(shade)).display();
       \endcode
       \image html ref_mul.jpg
       \sa get_mul(),
           div(),
           operator*=(const CImg<t>&).
    **/
    template<typename t>
    CImg<T>& mul(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return mul(+img);
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)(*ptrd * *(ptrs++));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd * *(ptrs++));
      }
      return *this;
    }

    //! In-place pointwise multiplication \newinstance.
    template<typename t>
    CImg<_cimg_Tt> get_mul(const CImg<t>& img) const {
      return CImg<_cimg_Tt>(*this,false).mul(img);
    }

    //! In-place pointwise division.
    /**
       Similar to mul(const CImg<t>&), except that it performs a pointwise division instead of a multiplication.
       \sa get_div(const CImg<t>&) const,
           operator/=(const CImg<t>&)
    **/
    template<typename t>
    CImg<T>& div(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return div(+img);
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)(*ptrd / *(ptrs++));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)(*ptrd / *(ptrs++));
      }
      return *this;
    }

    //! In-place pointwise division \newinstance.
    template<typename t>
    CImg<_cimg_Tt> get_div(const CImg<t>& img) const {
      return CImg<_cimg_Tt>(*this,false).div(img);
    }

    //! Raise each pixel value to a specified power.
    /**
       Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its power \f$I_{(x,y,z,c)}^p\f$.
       \param p : Used exponent.
       \note
       - The \inplace of this method statically casts the computed values to the pixel type \c T.
       - The \newinstance returns a \c CImg<float> image, if the pixel type \c T is \e not float-valued.
       \par Sample code :
       \code
       const CImg<float>
         img0("reference.jpg"),           // Load reference color image.
         img1 = (img0/255).pow(1.8)*=255, // Compute gamma correction, with gamma = 1.8.
         img2 = (img0/255).pow(0.5)*=255; // Compute gamma correction, with gamma = 0.5.
       (img0,img1,img2).display();
       \endcode
       \image html ref_pow.jpg
       \sa get_pow(double) const,
           pow(const char*),
           pow(const CImg<t>&),
           sqr(),
           sqrt(),
           exp(),
           log(),
           log10().
    **/
    CImg<T>& pow(const double p) {
      if (p==0) return fill(1);
      if (p==0.5) { cimg_for(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)std::sqrt((double)val); } return *this; }
      if (p==1) return *this;
      if (p==2) { cimg_for(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val; } return *this; }
      if (p==3) { cimg_for(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val; } return *this; }
      if (p==4) { cimg_for(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val*val; } return *this; }
      cimg_for(*this,ptrd,T) *ptrd = (T)std::pow((double)*ptrd,p);
      return *this;
    }

    //! Raise each pixel value to a specified power \newinstance.
    CImg<Tfloat> get_pow(const double p) const {
      return CImg<Tfloat>(*this,false).pow(p);
    }

    //! Raise each pixel value to a power, specified from an expression.
    /**
       Similar to operator+=(const char*), except it performs a pointwise exponentiation instead of an addition.
       \sa get_pow(const char*) const,
           pow(double),
           pow(CImg<t>&).
    **/
    CImg<T>& pow(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"pow");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)std::pow((double)*ptrd,mp.eval(x,y,z,c)); ++ptrd; }
      } catch (CImgException&) {
        CImg<Tfloat> values(_width,_height,_depth,_spectrum);
        try {
          values.fill(expression,true);
        } catch (CImgException&) {
          cimg::exception_mode() = omode;
          values.load(expression);
        }
        pow(values);
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    //! Raise each pixel value to a power, specified from an expression \newinstance.
    CImg<Tfloat> get_pow(const char *const expression) const {
      return CImg<Tfloat>(*this,false).pow(expression);
    }

    //! Raise each pixel value to a power, pointwisely specified from another image.
    /**
       Similar to operator+=(const CImg<t>& img), except that it performs an exponentiation instead of an addition.
       \sa get_pow(const CImg<t>&) const,
           pow(double),
           pow(const char*).
    **/
    template<typename t>
    CImg<T>& pow(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return pow(+img);
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)std::pow((double)*ptrd,(double)(*(ptrs++)));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)std::pow((double)*ptrd,(double)(*(ptrs++)));
      }
      return *this;
    }

    //! Raise each pixel value to a power, pointwisely specified from another image \newinstance.
    template<typename t>
    CImg<Tfloat> get_pow(const CImg<t>& img) const {
      return CImg<Tfloat>(*this,false).pow(img);
    }

    //! Compute the bitwise left rotation of each pixel value.
    /**
       Similar to operator<<=(unsigned int), except that it performs a left rotation instead of a left shift.
       \sa get_rol(unsigned int) const,
           rol(const char*),
           rol(const CImg<t>&),
           operator<<=(unsigned int),
           operator>>=(unsigned int).
    **/
    CImg<T>& rol(const unsigned int n=1) {
      cimg_for(*this,ptrd,T) *ptrd = (T)cimg::rol(*ptrd,n);
      return *this;
    }

    //! Compute the bitwise left rotation of each pixel value \newinstance.
    CImg<T> get_rol(const unsigned int n=1) const {
      return (+*this).rol(n);
    }

    //! Compute the bitwise left rotation of each pixel value.
    /**
       Similar to operator<<=(const char*), except that it performs a left rotation instead of a left shift.
       \sa get_rol(const char*) const,
           rol(unsigned int),
           rol(const CImg<t>&),
           operator<<=(const char*),
           operator>>=(const char*).
    **/
    CImg<T>& rol(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"rol");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::rol(*ptrd,(unsigned int)mp.eval(x,y,z,c)); ++ptrd; }
      } catch (CImgException&) {
        CImg<Tfloat> values(_width,_height,_depth,_spectrum);
        try {
          values.fill(expression,true);
        } catch (CImgException&) {
          cimg::exception_mode() = omode;
          values.load(expression);
        }
        rol(values);
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    //! Compute the bitwise left rotation of each pixel value \newinstance.
    CImg<T> get_rol(const char *const expression) const {
      return (+*this).rol(expression);
    }

    //! Compute the bitwise left rotation of each pixel value.
    /**
       Similar to operator<<=(const CImg<t>&), except that it performs a left rotation instead of a left shift.
       \sa get_rol(const CImg<t>&) const,
           rol(unsigned int),
           rol(const char*),
           operator<<=(const CImg<t>&),
           operator>>=(const CImg<t>&).
    **/
    template<typename t>
    CImg<T>& rol(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return rol(+img);
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)cimg::rol(*ptrd,(unsigned int)(*(ptrs++)));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)cimg::rol(*ptrd,(unsigned int)(*(ptrs++)));
      }
      return *this;
    }

    //! Compute the bitwise left rotation of each pixel value \newinstance.
    template<typename t>
    CImg<T> get_rol(const CImg<t>& img) const {
      return (+*this).rol(img);
    }

    //! Compute the bitwise right rotation of each pixel value.
    /**
       Similar to operator>>=(unsigned int), except that it performs a right rotation instead of a right shift.
       \sa get_ror(unsigned int) const,
           ror(const char*),
           ror(const CImg<t>&),
           operator<<=(unsigned int),
           operator>>=(unsigned int).
    **/
    CImg<T>& ror(const unsigned int n=1) {
      cimg_for(*this,ptrd,T) *ptrd = (T)cimg::ror(*ptrd,n);
      return *this;
    }

    //! Compute the bitwise right rotation of each pixel value \newinstance.
    CImg<T> get_ror(const unsigned int n=1) const {
      return (+*this).ror(n);
    }

    //! Compute the bitwise right rotation of each pixel value.
    /**
       Similar to operator>>=(const char*), except that it performs a right rotation instead of a right shift.
       \sa get_ror(const char*) const,
           ror(unsigned int),
           ror(const CImg<t>&),
           operator<<=(const char*),
           operator>>=(const char*).
    **/
    CImg<T>& ror(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"ror");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::ror(*ptrd,(unsigned int)mp.eval(x,y,z,c)); ++ptrd; }
      } catch (CImgException&) {
        CImg<Tfloat> values(_width,_height,_depth,_spectrum);
        try {
          values.fill(expression,true);
        } catch (CImgException&) {
          cimg::exception_mode() = omode;
          values.load(expression);
        }
        ror(values);
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    //! Compute the bitwise right rotation of each pixel value \newinstance.
    CImg<T> get_ror(const char *const expression) const {
      return (+*this).ror(expression);
    }

    //! Compute the bitwise right rotation of each pixel value.
    /**
       Similar to operator>>=(const CImg<t>&), except that it performs a right rotation instead of a right shift.
       \sa get_ror(const CImg<t>&),
           ror(unsigned int),
           ror(const char *),
           operator<<=(const CImg<t>&),
           operator>>=(const CImg<t>&).
    **/
    template<typename t>
    CImg<T>& ror(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return ror(+img);
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)cimg::ror(*ptrd,(unsigned int)(*(ptrs++)));
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = (T)cimg::ror(*ptrd,(unsigned int)(*(ptrs++)));
      }
      return *this;
    }

    //! Compute the bitwise right rotation of each pixel value \newinstance.
    template<typename t>
    CImg<T> get_ror(const CImg<t>& img) const {
      return (+*this).ror(img);
    }

    //! Pointwise min operator between an image and a value.
    CImg<T>& min(const T val) {
      cimg_for(*this,ptrd,T) *ptrd = cimg::min(*ptrd,val);
      return *this;
    }

    CImg<T> get_min(const T val) const {
      return (+*this).min(val);
    }

    //! Pointwise min operator between two images.
    template<typename t>
    CImg<T>& min(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return min(+img);
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = cimg::min((T)*(ptrs++),*ptrd);
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = cimg::min((T)*(ptrs++),*ptrd);
      }
      return *this;
    }

    template<typename t>
    CImg<_cimg_Tt> get_min(const CImg<t>& img) const {
      return CImg<_cimg_Tt>(*this,false).min(img);
    }

    //! Pointwise min operator between an image and a string.
    CImg<T>& min(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"min");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::min(*ptrd,(T)mp.eval(x,y,z,c)); ++ptrd; }
      } catch (CImgException&) {
        CImg<T> values(_width,_height,_depth,_spectrum);
        try {
          values.fill(expression,true);
        } catch (CImgException&) {
          cimg::exception_mode() = omode;
          values.load(expression);
        }
        min(values);
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    CImg<Tfloat> get_min(const char *const expression) const {
      return CImg<Tfloat>(*this,false).min(expression);
    }

    //! Pointwise max operator between an image and a value.
    CImg<T>& max(const T val) {
      cimg_for(*this,ptrd,T) *ptrd = cimg::max(*ptrd,val);
      return *this;
    }

    CImg<T> get_max(const T val) const {
      return (+*this).max(val);
    }

    //! Pointwise max operator between two images.
    template<typename t>
    CImg<T>& max(const CImg<t>& img) {
      const unsigned int siz = size(), isiz = img.size();
      if (siz && isiz) {
        if (is_overlapped(img)) return max(+img);
        T *ptrd = _data, *const ptre = _data + siz;
        if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
          for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = cimg::max((T)*(ptrs++),*ptrd);
        for (const t *ptrs = img._data; ptrd<ptre; ++ptrd) *ptrd = cimg::max((T)*(ptrs++),*ptrd);
      }
      return *this;
    }

    template<typename t>
    CImg<_cimg_Tt> get_max(const CImg<t>& img) const {
      return CImg<_cimg_Tt>(*this,false).max(img);
    }

    //! Pointwise max operator between an image and a string.
    CImg<T>& max(const char *const expression) {
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try {
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"max");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::max(*ptrd,(T)mp.eval(x,y,z,c)); ++ptrd; }
      } catch (CImgException&) {
        CImg<T> values(_width,_height,_depth,_spectrum);
        try {
          values.fill(expression,true);
        } catch (CImgException&) {
          cimg::exception_mode() = omode;
          values.load(expression);
        }
        max(values);
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    CImg<Tfloat> get_max(const char *const expression) const {
      return CImg<Tfloat>(*this,false).max(expression);
    }

    //! Return a reference to the minimum pixel value of the image instance
    T& min() {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "min() : Empty instance.",
                                    cimg_instance);
      T *ptr_min = _data;
      T min_value = *ptr_min;
      cimg_for(*this,ptrs,T) if (*ptrs<min_value) min_value = *(ptr_min=ptrs);
      return *ptr_min;
    }

    const T& min() const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "min() : Empty instance.",
                                    cimg_instance);
      const T *ptr_min = _data;
      T min_value = *ptr_min;
      cimg_for(*this,ptrs,T) if (*ptrs<min_value) min_value = *(ptr_min=ptrs);
      return *ptr_min;
    }

    //! Return a reference to the maximum pixel value of the image instance
    T& max() {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "max() : Empty instance.",
                                    cimg_instance);
      T *ptr_max = _data;
      T max_value = *ptr_max;
      cimg_for(*this,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs);
      return *ptr_max;
    }

    const T& max() const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "max() : Empty instance.",
                                    cimg_instance);
      const T *ptr_max = _data;
      T max_value = *ptr_max;
      cimg_for(*this,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs);
      return *ptr_max;
    }

    //! Return a reference to the minimum pixel value and return also the maximum pixel value.
    template<typename t>
    T& min_max(t& max_val) {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "min_max() : Empty instance.",
                                    cimg_instance);
      T *ptr_min = _data;
      T min_value = *ptr_min, max_value = min_value;
      cimg_for(*this,ptrs,T) {
        const T val = *ptrs;
        if (val<min_value) { min_value = val; ptr_min = ptrs; }
        if (val>max_value) max_value = val;
      }
      max_val = (t)max_value;
      return *ptr_min;
    }

    template<typename t>
    const T& min_max(t& max_val) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "min_max() : Empty instance.",
                                    cimg_instance);
      const T *ptr_min = _data;
      T min_value = *ptr_min, max_value = min_value;
      cimg_for(*this,ptrs,T) {
        const T val = *ptrs;
        if (val<min_value) { min_value = val; ptr_min = ptrs; }
        if (val>max_value) max_value = val;
      }
      max_val = (t)max_value;
      return *ptr_min;
    }

    //! Return a reference to the maximum pixel value and return also the minimum pixel value.
    template<typename t>
    T& max_min(t& min_val) {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "max_min() : Empty instance.",
                                    cimg_instance);
      T *ptr_max = _data;
      T max_value = *ptr_max, min_value = max_value;
      cimg_for(*this,ptrs,T) {
        const T val = *ptrs;
        if (val>max_value) { max_value = val; ptr_max = ptrs; }
        if (val<min_value) min_value = val;
      }
      min_val = (t)min_value;
      return *ptr_max;
    }

    template<typename t>
    const T& max_min(t& min_val) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "max_min() : Empty instance.",
                                    cimg_instance);
      const T *ptr_max = _data;
      T max_value = *ptr_max, min_value = max_value;
      cimg_for(*this,ptrs,T) {
        const T val = *ptrs;
        if (val>max_value) { max_value = val; ptr_max = ptrs; }
        if (val<min_value) min_value = val;
      }
      min_val = (t)min_value;
      return *ptr_max;
    }

    //! Return the kth smallest element of the image.
    T kth_smallest(const unsigned int k) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "kth_smallest() : Empty instance.",
                                    cimg_instance);
      CImg<T> arr(*this);
      unsigned int l = 0, ir = size() - 1;
      for (;;) {
        if (ir<=l+1) {
          if (ir==l+1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]);
          return arr[k];
        } else {
          const unsigned int mid = (l + ir)>>1;
          cimg::swap(arr[mid],arr[l+1]);
          if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]);
          if (arr[l+1]>arr[ir]) cimg::swap(arr[l+1],arr[ir]);
          if (arr[l]>arr[l+1]) cimg::swap(arr[l],arr[l+1]);
          unsigned int i = l + 1, j = ir;
          const T pivot = arr[l+1];
          for (;;) {
            do ++i; while (arr[i]<pivot);
            do --j; while (arr[j]>pivot);
            if (j<i) break;
            cimg::swap(arr[i],arr[j]);
          }
          arr[l+1] = arr[j];
          arr[j] = pivot;
          if (j>=k) ir = j - 1;
          if (j<=k) l = i;
        }
      }
      return 0;
    }

    //! Return the median value of the image.
    T median() const {
      const unsigned int s = size();
      const T res = kth_smallest(s>>1);
      return (s%2)?res:((res+kth_smallest((s>>1)-1))/2);
    }

    //! Return the sum of all the pixel values in an image.
    Tdouble sum() const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "sum() : Empty instance.",
                                    cimg_instance);
      Tdouble res = 0;
      cimg_for(*this,ptrs,T) res+=(Tdouble)*ptrs;
      return res;
    }

    //! Return the mean pixel value of the image instance.
    Tdouble mean() const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "mean() : Empty instance.",
                                    cimg_instance);
      Tdouble res = 0;
      cimg_for(*this,ptrs,T) res+=(Tdouble)*ptrs;
      return res/size();
    }

    //! Return the variance of the image.
    /**
       @param variance_method Determines how to calculate the variance
       <table border="0">
       <tr><td>0</td>
       <td>Second moment:
       @f$ v = 1/N \sum\limits_{k=1}^{N} (x_k - \bar x)^2
       = 1/N \left( \sum\limits_{k=1}^N x_k^2 - \left( \sum\limits_{k=1}^N x_k \right)^2 / N \right) @f$
       with @f$ \bar x = 1/N \sum\limits_{k=1}^N x_k \f$</td></tr>
       <tr><td>1</td>
       <td>Best unbiased estimator: @f$ v = \frac{1}{N-1} \sum\limits_{k=1}^{N} (x_k - \bar x)^2 @f$</td></tr>
       <tr><td>2</td>
       <td>Least median of squares</td></tr>
       <tr><td>3</td>
       <td>Least trimmed of squares</td></tr>
       </table>
    */
    Tdouble variance(const unsigned int variance_method=1) const {
      Tdouble foo;
      return variance_mean(variance_method,foo);
    }

    //! Return the variance and the mean of the image.
    template<typename t>
    Tdouble variance_mean(const unsigned int variance_method, t& mean) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "variance() : Empty instance.",
                                    cimg_instance);

      Tdouble variance = 0, average = 0;
      const unsigned int siz = size();
      switch (variance_method) {
      case 0 :{ // Least mean square (standard definition)
        Tdouble S = 0, S2 = 0;
        cimg_for(*this,ptrs,T) { const Tdouble val = (Tdouble)*ptrs; S+=val; S2+=val*val; }
        variance = (S2 - S*S/siz)/siz;
        average = S;
      } break;
      case 1 : { // Least mean square (robust definition)
        Tdouble S = 0, S2 = 0;
        cimg_for(*this,ptrs,T) { const Tdouble val = (Tdouble)*ptrs; S+=val; S2+=val*val; }
        variance = siz>1?(S2 - S*S/siz)/(siz - 1):0;
        average = S;
      } break;
      case 2 : { // Least Median of Squares (MAD)
        CImg<Tfloat> buf(*this);
        buf.sort();
        const unsigned int siz2 = siz>>1;
        const Tdouble med_i = (double)buf[siz2];
        cimg_for(buf,ptrs,Tfloat) { const Tdouble val = (Tdouble)*ptrs; *ptrs = (Tfloat)cimg::abs(val - med_i); average+=val; }
        buf.sort();
        const Tdouble sig = (Tdouble)(1.4828*buf[siz2]);
        variance = sig*sig;
      } break;
      default : { // Least trimmed of Squares
        CImg<Tfloat> buf(*this);
        const unsigned int siz2 = siz>>1;
        cimg_for(buf,ptrs,Tfloat) { const Tdouble val = (Tdouble)*ptrs; (*ptrs)=(Tfloat)((*ptrs)*val); average+=val; }
        buf.sort();
        Tdouble a = 0;
        const Tfloat *ptrs = buf._data;
        for (unsigned int j = 0; j<siz2; ++j) a+=(Tdouble)*(ptrs++);
        const Tdouble sig = (Tdouble)(2.6477*std::sqrt(a/siz2));
        variance = sig*sig;
      }
      }
      mean = (t)(average/siz);
      return variance>0?variance:0;
    }

    //! Estimate noise variance of the image instance.
    /**
       \param variance_method : method to compute the variance
       \note Because of structures such as edges in images it is
       recommanded to use a robust variance estimation. The variance of the
       noise is estimated by computing the variance of the Laplacian \f$(\Delta
       I)^2 \f$ scaled by a factor \f$c\f$ insuring \f$ c E[(\Delta I)^2]=
       \sigma^2\f$ where \f$\sigma\f$ is the noise variance.
       \see variance()
    **/
    Tdouble variance_noise(const unsigned int variance_method=2) const {
      const unsigned int siz = size();
      if (!siz || !_data) return 0;
      if (variance_method>1) { // Compute a scaled version of the Laplacian.
        CImg<Tdouble> tmp(*this);
        if (_depth==1) {
          const Tdouble cste = 1.0/std::sqrt(20.0); // Depends on how the Laplacian is computed.
          CImg_3x3(I,T);
          cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,T) {
            tmp(x,y,c) = cste*((Tdouble)Inc + (Tdouble)Ipc + (Tdouble)Icn +
                               (Tdouble)Icp - 4*(Tdouble)Icc);
          }
        } else {
          const Tdouble cste = 1.0/std::sqrt(42.0); // Depends on how the Laplacian is computed.
          CImg_3x3x3(I,T);
          cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,T) {
            tmp(x,y,z,c) = cste*(
                                 (Tdouble)Incc + (Tdouble)Ipcc + (Tdouble)Icnc + (Tdouble)Icpc +
                                 (Tdouble)Iccn + (Tdouble)Iccp - 6*(Tdouble)Iccc);
          }
        }
        return tmp.variance(variance_method);
      }

      // Version that doesn't need intermediate images.
      Tdouble variance = 0, S = 0, S2 = 0;
      if (_depth==1) {
        const Tdouble cste = 1.0/std::sqrt(20.0);
        CImg_3x3(I,T);
        cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,T) {
          const Tdouble val = cste*((Tdouble)Inc + (Tdouble)Ipc +
                                    (Tdouble)Icn + (Tdouble)Icp - 4*(Tdouble)Icc);
          S+=val; S2+=val*val;
        }
      } else {
        const Tdouble cste = 1.0/std::sqrt(42.0);
        CImg_3x3x3(I,T);
        cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,T) {
          const Tdouble val = cste *
            ((Tdouble)Incc + (Tdouble)Ipcc + (Tdouble)Icnc +
             (Tdouble)Icpc +
             (Tdouble)Iccn + (Tdouble)Iccp - 6*(Tdouble)Iccc);
          S+=val; S2+=val*val;
        }
      }
      if (variance_method) variance = siz>1?(S2 - S*S/siz)/(siz - 1):0;
      else variance = (S2 - S*S/siz)/siz;
      return variance>0?variance:0;
    }

    //! Compute the MSE (Mean-Squared Error) between two images.
    template<typename t>
    Tdouble MSE(const CImg<t>& img) const {
      if (img.size()!=size())
        throw CImgArgumentException(_cimg_instance
                                    "MSE() : Instance and specified image (%u,%u,%u,%u,%p) have different dimensions.",
                                    cimg_instance,
                                    img._width,img._height,img._depth,img._spectrum,img._data);
      Tdouble vMSE = 0;
      const t* ptr2 = img.end();
      cimg_for(*this,ptr1,T) {
        const Tdouble diff = (Tdouble)*ptr1 - (Tdouble)*(--ptr2);
        vMSE+=diff*diff;
      }
      vMSE/=img.size();
      return vMSE;
    }

    //! Compute the PSNR between two images.
    template<typename t>
    Tdouble PSNR(const CImg<t>& img, const Tdouble valmax=255) const {
      const Tdouble vMSE = (Tdouble)std::sqrt(MSE(img));
      return (vMSE!=0)?(Tdouble)(20*std::log10(valmax/vMSE)):(Tdouble)(cimg::type<Tdouble>::max());
    }

    //! Evaluate math expression.
    /**
       If you make successive evaluations on the same image and with the same expression,
       you can set 'expr' to 0 after the first call, to skip the math parsing step.
    **/
    double eval(const char *const expression, const double x=0, const double y=0, const double z=0, const double c=0) const {
      static _cimg_math_parser *mp = 0;
      if (expression) { delete mp; mp = 0; mp = new _cimg_math_parser(*this,expression,"eval"); }
      if (!mp)
        throw CImgArgumentException(_cimg_instance
                                    "eval() : No expression has been previously specified.",
                                    cimg_instance);
      return mp->eval(x,y,z,c);
    }

    //! Compute a statistics vector (min,max,mean,variance,xmin,ymin,zmin,cmin,xmax,ymax,zmax,cmax).
    CImg<T>& stats(const unsigned int variance_method=1) {
      return get_stats(variance_method).move_to(*this);
    }

    CImg<Tdouble> get_stats(const unsigned int variance_method=1) const {
      if (is_empty()) return CImg<doubleT>();
      const unsigned int siz = size();
      const T *const odata = _data;
      const T *pm = odata, *pM = odata;
      Tdouble S = 0, S2 = 0;
      T m = *pm, M = m;
      cimg_for(*this,ptrs,T) {
        const T val = *ptrs;
        const Tdouble _val = (Tdouble)val;
        if (val<m) { m = val; pm = ptrs; }
        if (val>M) { M = val; pM = ptrs; }
        S+=_val;
        S2+=_val*_val;
      }
      const Tdouble
        mean_value = S/siz,
        _variance_value = variance_method==0?(S2 - S*S/siz)/siz:
        (variance_method==1?(siz>1?(S2 - S*S/siz)/(siz - 1):0):
         variance(variance_method)),
        variance_value = _variance_value>0?_variance_value:0;
      int
        xm = 0, ym = 0, zm = 0, cm = 0,
        xM = 0, yM = 0, zM = 0, cM = 0;
      contains(*pm,xm,ym,zm,cm);
      contains(*pM,xM,yM,zM,cM);
      return CImg<Tdouble>(1,12).fill((Tdouble)m,(Tdouble)M,mean_value,variance_value,
                                      (Tdouble)xm,(Tdouble)ym,(Tdouble)zm,(Tdouble)cm,
                                      (Tdouble)xM,(Tdouble)yM,(Tdouble)zM,(Tdouble)cM);
    }

    //@}
    //-------------------------------------
    //
    //! \name Vector / Matrix Operations
    //@{
    //-------------------------------------

    //! Return the norm of the current vector/matrix. \p ntype = norm type (0=L2, 1=L1, -1=Linf).
    Tdouble magnitude(const int magnitude_type=2) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "magnitude() : Empty instance.",
                                    cimg_instance);
      Tdouble res = 0;
      switch (magnitude_type) {
      case -1 : {
        cimg_for(*this,ptrs,T) { const Tdouble val = (Tdouble)cimg::abs(*ptrs); if (val>res) res = val; }
      } break;
      case 1 : {
        cimg_for(*this,ptrs,T) res+=(Tdouble)cimg::abs(*ptrs);
      } break;
      default : {
        cimg_for(*this,ptrs,T) res+=(Tdouble)cimg::sqr(*ptrs);
        res = (Tdouble)std::sqrt(res);
      }
      }
      return res;
    }

    //! Return the trace of the image, viewed as a matrix.
    Tdouble trace() const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "trace() : Empty instance.",
                                    cimg_instance);
      Tdouble res = 0;
      cimg_forX(*this,k) res+=(Tdouble)(*this)(k,k);
      return res;
    }

    //! Return the determinant of the image, viewed as a matrix.
    Tdouble det() const {
      if (is_empty() || _width!=_height || _depth!=1 || _spectrum!=1)
        throw CImgInstanceException(_cimg_instance
                                    "det() : Instance is empty or not a square matrix.",
                                    cimg_instance);

      switch (_width) {
      case 1 : return (Tdouble)((*this)(0,0));
      case 2 : return (Tdouble)((*this)(0,0))*(Tdouble)((*this)(1,1)) - (Tdouble)((*this)(0,1))*(Tdouble)((*this)(1,0));
      case 3 : {
        const Tdouble
          a = (Tdouble)_data[0], d = (Tdouble)_data[1], g = (Tdouble)_data[2],
          b = (Tdouble)_data[3], e = (Tdouble)_data[4], h = (Tdouble)_data[5],
          c = (Tdouble)_data[6], f = (Tdouble)_data[7], i = (Tdouble)_data[8];
        return i*a*e - a*h*f - i*b*d + b*g*f + c*d*h - c*g*e;
      }
      default : {
        CImg<Tfloat> lu(*this);
        CImg<uintT> indx;
        bool d;
        lu._LU(indx,d);
        Tdouble res = d?(Tdouble)1:(Tdouble)-1;
        cimg_forX(lu,i) res*=lu(i,i);
        return res;
      }
      }
      return 0;
    }

    //! Return the dot product of the current vector/matrix with the vector/matrix \p img.
    template<typename t>
    Tdouble dot(const CImg<t>& img) const {
      if (is_empty())
        throw CImgInstanceException(_cimg_instance
                                    "dot() : Empty instance.",
                                    cimg_instance);
      if (!img)
        throw CImgArgumentException(_cimg_instance
                                    "dot() : Empty specified image.",
                                    cimg_instance);

      const unsigned int nb = cimg::min(size(),img.size());
      Tdouble res = 0;
      for (unsigned int off = 0; off<nb; ++off) res+=(Tdouble)_data[off]*(Tdouble)img[off];
      return res;
    }

    //! Return a new image corresponding to the vector located at (\p x,\p y,\p z) of the current vector-valued image.
    CImg<T> get_vector_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
      _cimg_static CImg<T> res;
      if (res._height!=_spectrum) res.assign(1,_spectrum);
      const unsigned int whd = _width*_height*_depth;
      const T *ptrs = data(x,y,z);
      T *ptrd = res._data;
      cimg_forC(*this,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
      return res;
    }

    //! Return a new image corresponding to the \a square \a matrix located at (\p x,\p y,\p z) of the current vector-valued image.
    CImg<T> get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {
      const int n = (int)std::sqrt((double)_spectrum);
      const T *ptrs = data(x,y,z,0);
      const unsigned int whd = _width*_height*_depth;
      CImg<T> res(n,n);
      T *ptrd = res._data;
      cimg_forC(*this,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
      return res;
    }

    //! Return a new image corresponding to the \a diffusion \a tensor located at (\p x,\p y,\p z) of the current vector-valued image.
    CImg<T> get_tensor_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
      const T *ptrs = data(x,y,z,0);
      const unsigned int whd = _width*_height*_depth;
      if (_spectrum==6) return tensor(*ptrs,*(ptrs+whd),*(ptrs+2*whd),*(ptrs+3*whd),*(ptrs+4*whd),*(ptrs+5*whd));
      if (_spectrum==3) return tensor(*ptrs,*(ptrs+whd),*(ptrs+2*whd));
      return tensor(*ptrs);
    }

    //! Set the image \p vec as the \a vector \a valued pixel located at (\p x,\p y,\p z) of the current vector-valued image.
    template<typename t>
    CImg<T>& set_vector_at(const CImg<t>& vec, const unsigned int x, const unsigned int y=0, const unsigned int z=0) {
      if (x<_width && y<_height && z<_depth) {
        const t *ptrs = vec._data;
        const unsigned int whd = _width*_height*_depth;
        T *ptrd = data(x,y,z);
        for (unsigned int k = cimg::min((unsigned int)vec.size(),_spectrum); k; --k) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
      }
      return *this;
    }

    //! Set the image \p vec as the \a square \a matrix-valued pixel located at (\p x,\p y,\p z) of the current vector-valued image.
    template<typename t>
    CImg<T>& set_matrix_at(const CImg<t>& mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
      return set_vector_at(mat,x,y,z);
    }

    //! Set the image \p vec as the \a tensor \a valued pixel located at (\p x,\p y,\p z) of the current vector-valued image.
    template<typename t>
    CImg<T>& set_tensor_at(const CImg<t>& ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
      T *ptrd = data(x,y,z,0);
      const unsigned int siz = _width*_height*_depth;
      if (ten._height==2) {
        *ptrd = (T)ten[0]; ptrd+=siz;
        *ptrd = (T)ten[1]; ptrd+=siz;
        *ptrd = (T)ten[3];
      }
      else {
        *ptrd = (T)ten[0]; ptrd+=siz;
        *ptrd = (T)ten[1]; ptrd+=siz;
        *ptrd = (T)ten[2]; ptrd+=siz;
        *ptrd = (T)ten[4]; ptrd+=siz;
        *ptrd = (T)ten[5]; ptrd+=siz;
        *ptrd = (T)ten[8];
      }
      return *this;
    }

    //! Unroll all images values into a one-column vector.
    CImg<T>& vector() {
      return unroll('y');
    }

    CImg<T> get_vector() const {
      return get_unroll('y');
    }

    //! Realign pixel values of the image instance as a square matrix
    CImg<T>& matrix() {
      const unsigned int siz = size();
      switch (siz) {
      case 1 : break;
      case 4 : _width = _height = 2; break;
      case 9 : _width = _height = 3; break;
      case 16 : _width = _height = 4; break;
      case 25 : _width = _height = 5; break;
      case 36 : _width = _height = 6; break;
      case 49 : _width = _height = 7; break;
      case 64 : _width = _height = 8; break;
      case 81 : _width = _height = 9; break;
      case 100 : _width = _height = 10; break;
      default : {
        unsigned int i = 11, i2 = i*i;
        while (i2<siz) { i2+=2*i + 1; ++i; }
        if (i2==siz) _width = _height = i;
        else throw CImgInstanceException(_cimg_instance
                                         "matrix() : Invalid instance size %u (should be a square integer).",
                                         cimg_instance,
                                         siz);
      }
      }
      return *this;
    }

    CImg<T> get_matrix() const {
      return (+*this).matrix();
    }

    //! Realign pixel values of the image instance as a symmetric tensor.
    CImg<T>& tensor() {
      return get_tensor().move_to(*this);
    }

    CImg<T> get_tensor() const {
      CImg<T> res;
      const unsigned int siz = size();
      switch (siz) {
      case 1 : break;
      case 3 :
        res.assign(2,2);
        res(0,0) = (*this)(0);
        res(1,0) = res(0,1) = (*this)(1);
        res(1,1) = (*this)(2);
        break;
      case 6 :
        res.assign(3,3);
        res(0,0) = (*this)(0);
        res(1,0) = res(0,1) = (*this)(1);
        res(2,0) = res(0,2) = (*this)(2);
        res(1,1) = (*this)(3);
        res(2,1) = res(1,2) = (*this)(4);
        res(2,2) = (*this)(5);
        break;
      default :
        throw CImgInstanceException(_cimg_instance
                                    "tensor() : Invalid instance size (does not define a 1x1, 2x2 or 3x3 tensor).",
                                    cimg_instance);
      }
      return res;
    }

    //! Get a diagonal matrix, whose diagonal coefficients are the coefficients of the input image.
    CImg<T>& diagonal() {
      return get_diagonal().move_to(*this);
    }

    CImg<T> get_diagonal() const {
      if (is_empty()) return *this;
      CImg<T> res(size(),size(),1,1,0);
      cimg_foroff(*this,off) res(off,off) = (*this)(off);
      return res;
    }

    //! Get an identity matrix having same dimension than image instance.
    CImg<T>& identity_matrix() {
      return identity_matrix(cimg::max(_width,_height)).move_to(*this);
    }

    CImg<T> get_identity_matrix() const {
      return identity_matrix(cimg::max(_width,_height));
    }

    //! Return a N-numbered sequence vector from \p a0 to \p a1.
    CImg<T>& sequence(const T a0, const T a1) {
      if (is_empty()) return *this;
      const unsigned int siz = size() - 1;
      T* ptr = _data;
      if (siz) {
        const Tdouble delta = (Tdouble)a1 - (Tdouble)a0;
        cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz);
      } else *ptr = a0;
      return *this;
    }

    CImg<T> get_sequence(const T a0, const T a1) const {
      return (+*this).sequence(a0,a1);
    }

    //! Transpose the current matrix.
    CImg<T>& transpose() {
      if (_width==1) { _width = _height; _height = 1; return *this; }
      if (_height==1) { _height = _width; _width = 1; return *this; }
      if (_width==_height) {
        cimg_forYZC(*this,y,z,c) for (int x = y; x<width(); ++x) cimg::swap((*this)(x,y,z,c),(*this)(y,x,z,c));
        return *this;
      }
      return get_transpose().move_to(*this);
    }

    CImg<T> get_transpose() const {
      return get_permute_axes("yxzc");
    }

    //! Compute the cross product between two 3d vectors.
    template<typename t>
    CImg<T>& cross(const CImg<t>& img) {
      if (_width!=1 || _height<3 || img._width!=1 || img._height<3)
        throw CImgInstanceException(_cimg_instance
                                    "cross() : Instance and/or specified image (%u,%u,%u,%u,%p) are not 3d vectors.",
                                    cimg_instance,
                                    img._width,img._height,img._depth,img._spectrum,img._data);

      const T x = (*this)[0], y = (*this)[1], z = (*this)[2];
      (*this)[0] = (T)(y*img[2] - z*img[1]);
      (*this)[1] = (T)(z*img[0] - x*img[2]);
      (*this)[2] = (T)(x*img[1] - y*img[0]);
      return *this;
    }

    template<typename t>
    CImg<_cimg_Tt> get_cross(const CImg<t>& img) const {
      return CImg<_cimg_Tt>(*this).cross(img);
    }

    //! Invert the current matrix.
    CImg<T>& invert(const bool use_LU=true) {
      if (_width!=_height || _depth!=1 || _spectrum!=1)
        throw CImgInstanceException(_cimg_instance
                                    "invert() : Instance is not a square matrix.",
                                    cimg_instance);
#ifdef cimg_use_lapack
      int INFO = (int)use_LU, N = _width, LWORK = 4*N, *const IPIV = new int[N];
      Tfloat
        *const lapA = new Tfloat[N*N],
        *const WORK = new Tfloat[LWORK];
      cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
      cimg::getrf(N,lapA,IPIV,INFO);
      if (INFO)
        cimg::warn(_cimg_instance
                   "invert() : LAPACK function dgetrf_() returned error code %d.",
                   cimg_instance,
                   INFO);
      else {
        cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO);
        if (INFO)
          cimg::warn(_cimg_instance
                     "invert() : LAPACK function dgetri_() returned error code %d.",
                     cimg_instance,
                     INFO);
      }
      if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N+l]); else fill(0);
      delete[] IPIV; delete[] lapA; delete[] WORK;
#else
      const double dete = _width>3?-1.0:det();
      if (dete!=0.0 && _width==2) {
        const double
          a = _data[0], c = _data[1],
          b = _data[2], d = _data[3];
        _data[0] = (T)(d/dete); _data[1] = (T)(-c/dete);
        _data[2] = (T)(-b/dete); _data[3] = (T)(a/dete);
      } else if (dete!=0.0 && _width==3) {
        const double
          a = _data[0], d = _data[1], g = _data[2],
          b = _data[3], e = _data[4], h = _data[5],
          c = _data[6], f = _data[7], i = _data[8];
        _data[0] = (T)((i*e-f*h)/dete), _data[1] = (T)((g*f-i*d)/dete), _data[2] = (T)((d*h-g*e)/dete);
        _data[3] = (T)((h*c-i*b)/dete), _data[4] = (T)((i*a-c*g)/dete), _data[5] = (T)((g*b-a*h)/dete);
        _data[6] = (T)((b*f-e*c)/dete), _data[7] = (T)((d*c-a*f)/dete), _data[8] = (T)((a*e-d*b)/dete);
      } else {
        if (use_LU) { // LU-based inverse computation
          CImg<Tfloat> A(*this), indx, col(1,_width);
          bool d;
          A._LU(indx,d);
          cimg_forX(*this,j) {
            col.fill(0);
            col(j) = 1;
            col._solve(A,indx);
            cimg_forX(*this,i) (*this)(j,i) = (T)col(i);
          }
        } else { // SVD-based inverse computation
          CImg<Tfloat> U(_width,_width), S(1,_width), V(_width,_width);
          SVD(U,S,V,false);
          U.transpose();
          cimg_forY(S,k) if (S[k]!=0) S[k]=1/S[k];
          S.diagonal();
          *this = V*S*U;
        }
      }
#endif
      return *this;
    }

    CImg<Tfloat> get_invert(const bool use_LU=true) const {
      return CImg<Tfloat>(*this,false).invert(use_LU);
    }

    //! Compute the pseudo-inverse (Moore-Penrose) of the matrix.
    CImg<T>& pseudoinvert() {
      return get_pseudoinvert().move_to(*this);
    }

    CImg<Tfloat> get_pseudoinvert() const {
      CImg<Tfloat> U, S, V;
      SVD(U,S,V);
      cimg_forX(V,x) {
        const Tfloat s = S(x), invs = s!=0?1/s:(Tfloat)0;
        cimg_forY(V,y) V(x,y)*=invs;
      }
      return V*U.transpose();
    }

    //! Solve a linear system AX=B where B=*this.
    template<typename t>
    CImg<T>& solve(const CImg<t>& A) {
      if (_width!=1 || _depth!=1 || _spectrum!=1 || _height!=A._height || A._depth!=1 || A._spectrum!=1)
        throw CImgArgumentException(_cimg_instance
                                    "solve() : Instance and specified matrix (%u,%u,%u,%u,%p) have incompatible dimensions.",
                                    cimg_instance,
                                    A._width,A._height,A._depth,A._spectrum,A._data);
      typedef _cimg_Ttfloat Ttfloat;
      if (A._width==A._height) {
#ifdef cimg_use_lapack
        char TRANS = 'N';
        int INFO, N = _height, LWORK = 4*N, one = 1, *const IPIV = new int[N];
        Ttfloat
          *const lapA = new Ttfloat[N*N],
          *const lapB = new Ttfloat[N],
          *const WORK = new Ttfloat[LWORK];
        cimg_forXY(A,k,l) lapA[k*N+l] = (Ttfloat)(A(k,l));
        cimg_forY(*this,i) lapB[i] = (Ttfloat)((*this)(i));
        cimg::getrf(N,lapA,IPIV,INFO);
        if (INFO)
          cimg::warn(_cimg_instance
                     "solve() : LAPACK library function dgetrf_() returned error code %d.",
                     cimg_instance,
                     INFO);

        if (!INFO) {
          cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO);
          if (INFO)
            cimg::warn(_cimg_instance
                       "solve() : LAPACK library function dgetrs_() returned error code %d.",
                       cimg_instance,
                       INFO);
        }
        if (!INFO) cimg_forY(*this,i) (*this)(i) = (T)(lapB[i]); else fill(0);
        delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK;
#else
        CImg<Ttfloat> lu(A,false);
        CImg<Ttfloat> indx;
        bool d;
        lu._LU(indx,d);
        _solve(lu,indx);
#endif
      } else assign(A.get_pseudoinvert()*(*this));
      return *this;
    }

    template<typename t>
    CImg<_cimg_Ttfloat> get_solve(const CImg<t>& A) const {
      return CImg<_cimg_Ttfloat>(*this,false).solve(A);
    }

    template<typename t, typename ti>
    CImg<T>& _solve(const CImg<t>& A, const CImg<ti>& indx) {
      typedef _cimg_Ttfloat Ttfloat;
      const int N = size();
      int ii = -1;
      Ttfloat sum;
      for (int i = 0; i<N; ++i) {
        const int ip = (int)indx[i];
        Ttfloat sum = (*this)(ip);
        (*this)(ip) = (*this)(i);
        if (ii>=0) for (int j = ii; j<=i-1; ++j) sum-=A(j,i)*(*this)(j);
        else if (sum!=0) ii = i;
        (*this)(i) = (T)sum;
      }
      for (int i = N - 1; i>=0; --i) {
        sum = (*this)(i);
        for (int j = i + 1; j<N; ++j) sum-=A(j,i)*(*this)(j);
        (*this)(i) = (T)(sum/A(i,i));
      }
      return *this;
    }

    //! Solve a linear system AX=B where B=*this and A is a tridiagonal matrix A = [ b0,c0,0,...; a1,b1,c1,0,... ; ... ; ...,0,aN,bN ],
    // stored as a 3 columns matrix (resolution uses the Thomas Algorithm).
    template<typename t>
    CImg<T>& solve_tridiagonal(const CImg<t>& A) {
      const unsigned int siz = (int)size();
      if (A._width!=3 || A._height!=siz)
        throw CImgArgumentException(_cimg_instance
                                    "solve_tridiagonal() : Instance and tridiagonal matrix "
                                    "(%u,%u,%u,%u,%p) have incompatible dimensions.",
                                    cimg_instance,
                                    A._width,A._height,A._depth,A._spectrum,A._data);
      typedef _cimg_Ttfloat Ttfloat;
      const Ttfloat epsilon = 1e-4;
      CImg<Ttfloat> B = A.get_column(1), V(*this,false);
      for (int i = 1; i<(int)siz; ++i) {
        const Ttfloat m = A(0,i)/(B[i-1]?B[i-1]:epsilon);
        B[i] -= m*A(2,i-1);
        V[i] -= m*V[i-1];
      }
      (*this)[siz-1] = (T)(V[siz-1]/(B[siz-1]?B[siz-1]:epsilon));
      for (int i = (int)siz - 2; i>=0; --i) (*this)[i] = (T)((V[i] - A(2,i)*(*this)[i+1])/(B[i]?B[i]:epsilon));
      return *this;
    }

    template<typename t>
    CImg<_cimg_Ttfloat> get_solve_tridiagonal(const CImg<t>& A) const {
      return CImg<_cimg_Ttfloat>(*this,false).solve_tridiagonal(A);
    }

    //! Compute the eigenvalues and eigenvectors of a matrix.
    template<typename t>
    const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {
      if (is_empty()) { val.assign(); vec.assign(); }
      else {
        if (_width!=_height || _depth>1 || _spectrum>1)
          throw CImgInstanceException(_cimg_instance
                                      "eigen() : Instance is not a square matrix.",
                                      cimg_instance);

        if (val.size()<_width) val.assign(1,_width);
        if (vec.size()<_width*_width) vec.assign(_width,_width);
        switch (_width) {
        case 1 : { val[0] = (t)(*this)[0]; vec[0] = (t)1; } break;
        case 2 : {
          const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a + d;
          double f = e*e - 4*(a*d - b*c);
          if (f<0)
            cimg::warn(_cimg_instance
                       "CImg<%s>::eigen() : Complex eigenvalues found.",
                       cimg_instance);

          f = std::sqrt(f);
          const double l1 = 0.5*(e-f), l2 = 0.5*(e+f);
          const double theta1 = std::atan2(l2-a,b), theta2 = std::atan2(l1-a,b);
          val[0] = (t)l2;
          val[1] = (t)l1;
          vec(0,0) = (t)std::cos(theta1);
          vec(0,1) = (t)std::sin(theta1);
          vec(1,0) = (t)std::cos(theta2);
          vec(1,1) = (t)std::sin(theta2);
        } break;
        default :
          throw CImgInstanceException(_cimg_instance
                                      "eigen() : Eigenvalues computation of general matrices is limited to 2x2 matrices.",
                                      cimg_instance);
        }
      }
      return *this;
    }

    CImgList<Tfloat> get_eigen() const {
      CImgList<Tfloat> res(2);
      eigen(res[0],res[1]);
      return res;
    }

    //! Compute the eigenvalues and eigenvectors of a symmetric matrix.
    template<typename t>
    const CImg<T>& symmetric_eigen(CImg<t>& val, CImg<t>& vec) const {
      if (is_empty()) { val.assign(); vec.assign(); }
      else {
#ifdef cimg_use_lapack
        char JOB = 'V', UPLO = 'U';
        int N = _width, LWORK = 4*N, INFO;
        Tfloat
          *const lapA = new Tfloat[N*N],
          *const lapW = new Tfloat[N],
          *const WORK = new Tfloat[LWORK];
        cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
        cimg::syev(JOB,UPLO,N,lapA,lapW,WORK,LWORK,INFO);
        if (INFO)
          cimg::warn(_cimg_instance
                     "symmetric_eigen() : LAPACK library function dsyev_() returned error code %d.",
                     cimg_instance,
                     INFO);

        val.assign(1,N);
        vec.assign(N,N);
        if (!INFO) {
          cimg_forY(val,i) val(i) = (T)lapW[N-1-i];
          cimg_forXY(vec,k,l) vec(k,l) = (T)(lapA[(N-1-k)*N+l]);
        } else { val.fill(0); vec.fill(0); }
        delete[] lapA; delete[] lapW; delete[] WORK;
#else
        if (_width!=_height || _depth>1 || _spectrum>1)
          throw CImgInstanceException(_cimg_instance
                                      "eigen() : Instance is not a square matrix.",
                                      cimg_instance);

        val.assign(1,_width);
        if (vec._data) vec.assign(_width,_width);
        if (_width<3) {
          eigen(val,vec);
          if (_width==2) { vec[1] = -vec[2]; vec[3] = vec[0]; } // Force orthogonality for 2x2 matrices.
          return *this;
        }
        CImg<t> V(_width,_width);
        SVD(vec,val,V,false);
        bool is_ambiguous = false;
        float eig = 0;
        cimg_forY(val,p) {       // check for ambiguous cases.
          if (val[p]>eig) eig = (float)val[p];
          t scal = 0;
          cimg_forY(vec,y) scal+=vec(p,y)*V(p,y);
          if (cimg::abs(scal)<0.9f) is_ambiguous = true;
          if (scal<0) val[p] = -val[p];
        }
        if (is_ambiguous) {
          ++(eig*=2);
          SVD(vec,val,V,false,40,eig);
          val-=eig;
        }
        CImg<intT> permutations;  // sort eigenvalues in decreasing order
        CImg<t> tmp(_width);
        val.sort(permutations,false);
        cimg_forY(vec,k) {
          cimg_forY(permutations,y) tmp(y) = vec(permutations(y),k);
          std::memcpy(vec.data(0,k),tmp._data,sizeof(t)*_width);
        }
#endif
      }
      return *this;
    }

    CImgList<Tfloat> get_symmetric_eigen() const {
      CImgList<Tfloat> res(2);
      symmetric_eigen(res[0],res[1]);
      return res;
    }

    //! Sort values of a vector and get corresponding permutations.
    template<typename t>
    CImg<T>& sort(CImg<t>& permutations, const bool increasing=true) {
      permutations.assign(_width,_height,_depth,_spectrum);
      if (is_empty()) return *this;
      cimg_foroff(permutations,off) permutations[off] = (t)off;
      return _quicksort(0,size()-1,permutations,increasing,true);
    }

    template<typename t>
    CImg<T> get_sort(CImg<t>& permutations, const bool increasing=true) const {
      return (+*this).sort(permutations,increasing);
    }

    //! Sort image values.
    CImg<T>& sort(const bool increasing=true, const char axis=0) {
      if (is_empty()) return *this;
      CImg<uintT> perm;
      switch (axis) {
      case 0 :
        _quicksort(0,size()-1,perm,increasing,false);
        break;
      case 'x' : {
        perm.assign(_width);
        get_crop(0,0,0,0,_width-1,0,0,0).sort(perm,increasing);
        CImg<T> img(*this,false);
        cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(perm[x],y,z,c);
      } break;
      case 'y' : {
        perm.assign(_height);
        get_crop(0,0,0,0,0,_height-1,0,0).sort(perm,increasing);
        CImg<T> img(*this,false);
        cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,perm[y],z,c);
      } break;
      case 'z' : {
        perm.assign(_depth);
        get_crop(0,0,0,0,0,0,_depth-1,0).sort(perm,increasing);
        CImg<T> img(*this,false);
        cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,y,perm[z],c);
      } break;
      case 'c' : {
        perm.assign(_spectrum);
        get_crop(0,0,0,0,0,0,0,_spectrum-1).sort(perm,increasing);
        CImg<T> img(*this,false);
        cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,y,z,perm[c]);
      } break;
      default :
        throw CImgArgumentException(_cimg_instance
                                    "sort() : Invalid specified axis '%c' "
                                    "(should be { x | y | z | c }).",
                                    cimg_instance,axis);
      }
      return *this;
    }

    CImg<T> get_sort(const bool increasing=true, const char axis=0) const {
      return (+*this).sort(increasing,axis);
    }

    template<typename t>
    CImg<T>& _quicksort(const int indm, const int indM, CImg<t>& permutations, const bool increasing, const bool is_permutations) {
      if (indm<indM) {
        const int mid = (indm + indM)/2;
        if (increasing) {
          if ((*this)[indm]>(*this)[mid]) {
            cimg::swap((*this)[indm],(*this)[mid]); if (is_permutations) cimg::swap(permutations[indm],permutations[mid]);
          }
          if ((*this)[mid]>(*this)[indM]) {
            cimg::swap((*this)[indM],(*this)[mid]); if (is_permutations) cimg::swap(permutations[indM],permutations[mid]);
          }
          if ((*this)[indm]>(*this)[mid]) {
            cimg::swap((*this)[indm],(*this)[mid]); if (is_permutations) cimg::swap(permutations[indm],permutations[mid]);
          }
        } else {
          if ((*this)[indm]<(*this)[mid]) {
            cimg::swap((*this)[indm],(*this)[mid]); if (is_permutations) cimg::swap(permutations[indm],permutations[mid]);
          }
          if ((*this)[mid]<(*this)[indM]) {
            cimg::swap((*this)[indM],(*this)[mid]); if (is_permutations) cimg::swap(permutations[indM],permutations[mid]);
          }
          if ((*this)[indm]<(*this)[mid]) {
            cimg::swap((*this)[indm],(*this)[mid]); if (is_permutations) cimg::swap(permutations[indm],permutations[mid]);
          }
        }
        if (indM - indm>=3) {
          const T pivot = (*this)[mid];
          int i = indm, j = indM;
          if (increasing) {
            do {
              while ((*this)[i]<pivot) ++i;
              while ((*this)[j]>pivot) --j;
              if (i<=j) {
                if (is_permutations) cimg::swap(permutations[i],permutations[j]);
                cimg::swap((*this)[i++],(*this)[j--]);
              }
            } while (i<=j);
          } else {
            do {
              while ((*this)[i]>pivot) ++i;
              while ((*this)[j]<pivot) --j;
              if (i<=j) {
                if (is_permutations) cimg::swap(permutations[i],permutations[j]);
                cimg::swap((*this)[i++],(*this)[j--]);
              }
            } while (i<=j);
          }
          if (indm<j) _quicksort(indm,j,permutations,increasing,is_permutations);
          if (i<indM) _quicksort(i,indM,permutations,increasing,is_permutations);
        }
      }
      return *this;
    }

    //! Compute the SVD of a general matrix.
    template<typename t>
    const CImg<T>& SVD(CImg<t>& U, CImg<t>& S, CImg<t>& V, const bool sorting=true,
                       const unsigned int max_iteration=40, const float lambda=0) const {
      if (is_empty()) { U.assign(); S.assign(); V.assign(); }
      else {
        U = *this;
        if (lambda!=0) {
          const unsigned int delta = cimg::min(U._width,U._height);
          for (unsigned int i = 0; i<delta; ++i) U(i,i) = (t)(U(i,i) + lambda);
        }
        if (S.size()<_width) S.assign(1,_width);
        if (V._width<_width || V._height<_height) V.assign(_width,_width);
        CImg<t> rv1(_width);
        t anorm = 0, c, f, g = 0, h, s, scale = 0;
        int l = 0, nm = 0;

        cimg_forX(U,i) {
          l = i+1; rv1[i] = scale*g; g = s = scale = 0;
          if (i<height()) {
            for (int k = i; k<height(); ++k) scale+= cimg::abs(U(i,k));
            if (scale) {
              for (int k = i; k<height(); ++k) { U(i,k)/=scale; s+= U(i,k)*U(i,k); }
              f = U(i,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h=f*g-s; U(i,i) = f-g;
              for (int j = l; j<width(); ++j) {
                s = 0;
                for (int k=i; k<height(); ++k) s+= U(i,k)*U(j,k);
                f = s/h;
                for (int k = i; k<height(); ++k) U(j,k)+= f*U(i,k);
              }
              for (int k = i; k<height(); ++k) U(i,k)*= scale;
            }
          }
          S[i]=scale*g;

          g = s = scale = 0;
          if (i<height() && i!=width()-1) {
            for (int k = l; k<width(); ++k) scale+=cimg::abs(U(k,i));
            if (scale) {
              for (int k = l; k<width(); ++k) { U(k,i)/= scale; s+= U(k,i)*U(k,i); }
              f = U(l,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h = f*g-s; U(l,i) = f-g;
              for (int k = l; k<width(); ++k) rv1[k]=U(k,i)/h;
              for (int j = l; j<height(); ++j) {
                s = 0;
                for (int k = l; k<width(); ++k) s+= U(k,j)*U(k,i);
                for (int k = l; k<width(); ++k) U(k,j)+= s*rv1[k];
              }
              for (int k = l; k<width(); ++k) U(k,i)*= scale;
            }
          }
          anorm = (t)cimg::max((float)anorm,(float)(cimg::abs(S[i])+cimg::abs(rv1[i])));
        }

        for (int i = width()-1; i>=0; --i) {
          if (i<width()-1) {
            if (g) {
              for (int j = l; j<width(); ++j) V(i,j) =(U(j,i)/U(l,i))/g;
              for (int j = l; j<width(); ++j) {
                s = 0;
                for (int k = l; k<width(); ++k) s+= U(k,i)*V(j,k);
                for (int k = l; k<width(); ++k) V(j,k)+= s*V(i,k);
              }
            }
            for (int j = l; j<width(); ++j) V(j,i) = V(i,j) = (t)0.0;
          }
          V(i,i) = (t)1.0; g = rv1[i]; l = i;
        }

        for (int i = cimg::min(width(),height())-1; i>=0; --i) {
          l = i+1; g = S[i];
          for (int j = l; j<width(); ++j) U(j,i) = 0;
          if (g) {
            g = 1/g;
            for (int j = l; j<width(); ++j) {
              s = 0; for (int k = l; k<height(); ++k) s+= U(i,k)*U(j,k);
              f = (s/U(i,i))*g;
              for (int k = i; k<height(); ++k) U(j,k)+= f*U(i,k);
            }
            for (int j = i; j<height(); ++j) U(i,j)*= g;
          } else for (int j = i; j<height(); ++j) U(i,j) = 0;
          ++U(i,i);
        }

        for (int k = width()-1; k>=0; --k) {
          for (unsigned int its = 0; its<max_iteration; ++its) {
            bool flag = true;
            for (l = k; l>=1; --l) {
              nm = l-1;
              if ((cimg::abs(rv1[l])+anorm)==anorm) { flag = false; break; }
              if ((cimg::abs(S[nm])+anorm)==anorm) break;
            }
            if (flag) {
              c = 0; s = 1;
              for (int i = l; i<=k; ++i) {
                f = s*rv1[i]; rv1[i] = c*rv1[i];
                if ((cimg::abs(f)+anorm)==anorm) break;
                g = S[i]; h = (t)cimg::_pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h;
                cimg_forY(U,j) { const t y = U(nm,j), z = U(i,j); U(nm,j) = y*c + z*s; U(i,j) = z*c - y*s; }
              }
            }
            const t z = S[k];
            if (l==k) { if (z<0) { S[k] = -z; cimg_forX(U,j) V(k,j) = -V(k,j); } break; }
            nm = k-1;
            t x = S[l], y = S[nm];
            g = rv1[nm]; h = rv1[k];
            f = ((y-z)*(y+z)+(g-h)*(g+h))/(2*h*y);
            g = (t)cimg::_pythagore(f,1.0);
            f = ((x-z)*(x+z)+h*((y/(f+ (f>=0?g:-g)))-h))/x;
            c = s = 1;
            for (int j = l; j<=nm; ++j) {
              const int i = j+1;
              g = rv1[i]; h = s*g; g = c*g;
              t y = S[i];
              t z = (t)cimg::_pythagore(f,h);
              rv1[j] = z; c = f/z; s = h/z;
              f = x*c+g*s; g = g*c-x*s; h = y*s; y*=c;
              cimg_forX(U,jj) { const t x = V(j,jj), z = V(i,jj); V(j,jj) = x*c + z*s; V(i,jj) = z*c - x*s; }
              z = (t)cimg::_pythagore(f,h); S[j] = z;
              if (z) { z = 1/z; c = f*z; s = h*z; }
              f = c*g+s*y; x = c*y-s*g;
              cimg_forY(U,jj) { const t y = U(j,jj); z = U(i,jj); U(j,jj) = y*c + z*s; U(i,jj) = z*c - y*s; }
            }
            rv1[l] = 0; rv1[k]=f; S[k]=x;
          }
        }

        if (sorting) {
          CImg<intT> permutations;
          CImg<t> tmp(_width);
          S.sort(permutations,false);
          cimg_forY(U,k) {
            cimg_forY(permutations,y) tmp(y) = U(permutations(y),k);
            std::memcpy(U.data(0,k),tmp._data,sizeof(t)*_width);
          }
          cimg_forY(V,k) {
            cimg_forY(permutations,y) tmp(y) = V(permutations(y),k);
            std::memcpy(V.data(0,k),tmp._data,sizeof(t)*_width);
          }
        }
      }
      return *this;
    }

    CImgList<Tfloat> get_SVD(const bool sorting=true,
                             const unsigned int max_iteration=40, const float lambda=0) const {
      CImgList<Tfloat> res(3);
      SVD(res[0],res[1],res[2],sorting,max_iteration,lambda);
      return res;
    }

    // INNER ROUTINE : Compute the LU decomposition of a permuted matrix (c.f. numerical recipies)
    template<typename t>
    CImg<T>& _LU(CImg<t>& indx, bool& d) {
      const int N = width();
      int imax = 0;
      CImg<Tfloat> vv(N);
      indx.assign(N);
      d = true;
      cimg_forX(*this,i) {
        Tfloat vmax = 0;
        cimg_forX(*this,j) {
          const Tfloat tmp = cimg::abs((*this)(j,i));
          if (tmp>vmax) vmax = tmp;
        }
        if (vmax==0) { indx.fill(0); return fill(0); }
        vv[i] = 1/vmax;
      }
      cimg_forX(*this,j) {
        for (int i = 0; i<j; ++i) {
          Tfloat sum=(*this)(j,i);
          for (int k = 0; k<i; ++k) sum-=(*this)(k,i)*(*this)(j,k);
          (*this)(j,i) = (T)sum;
        }
        Tfloat vmax = 0;
        for (int i = j; i<width(); ++i) {
          Tfloat sum=(*this)(j,i);
          for (int k = 0; k<j; ++k) sum-=(*this)(k,i)*(*this)(j,k);
          (*this)(j,i) = (T)sum;
          const Tfloat tmp = vv[i]*cimg::abs(sum);
          if (tmp>=vmax) { vmax=tmp; imax=i; }
        }
        if (j!=imax) {
          cimg_forX(*this,k) cimg::swap((*this)(k,imax),(*this)(k,j));
          d =!d;
          vv[imax] = vv[j];
        }
        indx[j] = (t)imax;
        if ((*this)(j,j)==0) (*this)(j,j) = (T)1e-20;
        if (j<N) {
          const Tfloat tmp = 1/(Tfloat)(*this)(j,j);
          for (int i=j+1; i<N; ++i) (*this)(j,i) = (T)((*this)(j,i)*tmp);
        }
      }
      return *this;
    }

    //! Compute minimal path in a graph, using the Dijkstra algorithm.
    /**
       \param distance An object having operator()(unsigned int i, unsigned int j) which returns distance between two nodes (i,j).
       \param nb_nodes Number of graph nodes.
       \param starting_node Indice of the starting node.
       \param ending_node Indice of the ending node (set to ~0U to ignore ending node).
       \param previous Array that gives the previous node indice in the path to the starting node (optional parameter).
       \return Array of distances of each node to the starting node.
    **/
    template<typename tf, typename t>
    static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
                            const unsigned int starting_node, const unsigned int ending_node,
                            CImg<t>& previous) {
      if (starting_node>=nb_nodes)
        throw CImgArgumentException("CImg<%s>::dijkstra() : Specified indice of starting node %u is higher than number of nodes %u.",
                                    pixel_type(),starting_node,nb_nodes);
      CImg<T> dist(1,nb_nodes,1,1,cimg::type<T>::max());
      dist(starting_node) = 0;
      previous.assign(1,nb_nodes,1,1,(t)-1);
      previous(starting_node) = (t)starting_node;
      CImg<uintT> Q(nb_nodes);
      cimg_forX(Q,u) Q(u) = u;
      cimg::swap(Q(starting_node),Q(0));
      unsigned int sizeQ = nb_nodes;
      while (sizeQ) {
        // Update neighbors from minimal vertex
        const unsigned int umin = Q(0);
        if (umin==ending_node) sizeQ = 0;
        else {
          const T dmin = dist(umin);
          const T infty = cimg::type<T>::max();
          for (unsigned int q = 1; q<sizeQ; ++q) {
            const unsigned int v = Q(q);
            const T d = (T)distance(v,umin);
            if (d<infty) {
              const T alt = dmin + d;
              if (alt<dist(v)) {
                dist(v) = alt;
                previous(v) = (t)umin;
                const T distpos = dist(Q(q));
                for (unsigned int pos = q, par = 0; pos && distpos<dist(Q(par=(pos+1)/2-1)); pos=par) cimg::swap(Q(pos),Q(par));
              }
            }
          }
          // Remove minimal vertex from queue
          Q(0) = Q(--sizeQ);
          const T distpos = dist(Q(0));
          for (unsigned int pos = 0, left = 0, right = 0;
               ((right=2*(pos+1),(left=right-1))<sizeQ && distpos>dist(Q(left))) || (right<sizeQ && distpos>dist(Q(right)));) {
            if (right<sizeQ) {
              if (dist(Q(left))<dist(Q(right))) { cimg::swap(Q(pos),Q(left)); pos = left; }
              else { cimg::swap(Q(pos),Q(right)); pos = right; }
            } else { cimg::swap(Q(pos),Q(left)); pos = left; }
          }
        }
      }
      return dist;
    }

    //! Return minimal path in a graph, using the Dijkstra algorithm.
    template<typename tf, typename t>
    static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
                            const unsigned int starting_node, const unsigned int ending_node=~0U) {
      CImg<uintT> foo;
      return dijkstra(distance,nb_nodes,starting_node,ending_node,foo);
    }

    //! Return minimal path in a graph, using the Dijkstra algorithm.
    /**
       image instance corresponds to the adjacency matrix of the graph.
       \param starting_node Indice of the starting node.
       \param previous Array that gives the previous node indice in the path to the starting node (optional parameter).
       \return Array of distances of each node to the starting node.
    **/
    template<typename t>
    CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) {
      return get_dijkstra(starting_node,ending_node,previous).move_to(*this);
    }

    template<typename t>
    CImg<T> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) const {
      if (_width!=_height || _depth!=1 || _spectrum!=1)
        throw CImgInstanceException(_cimg_instance
                                    "dijkstra() : Instance is not a graph adjacency matrix.",
                                    cimg_instance);

      return dijkstra(*this,_width,starting_node,ending_node,previous);
    }

    //! Return minimal path in a graph, using the Dijkstra algorithm.
    CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) {
      return get_dijkstra(starting_node,ending_node).move_to(*this);
    }

    CImg<Tfloat> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) const {
      CImg<uintT> foo;
      return get_dijkstra(starting_node,ending_node,foo);
    }

    //! Return stream line of a 2d or 3d vector field.
    CImg<floatT> get_streamline(const float x, const float y, const float z,
                                const float L=256, const float dl=0.1f,
                                const unsigned int interpolation_type=2, const bool is_backward_tracking=false,
                                const bool is_oriented_only=false) const {
      if (_spectrum!=2 && _spectrum!=3)
        throw CImgInstanceException(_cimg_instance
                                    "streamline() : Instance is not a 2d or 3d vector field.",
                                    cimg_instance);
      if (_spectrum==2) {
        if (is_oriented_only) {
          typename CImg<T>::_functor4d_streamline2d_oriented func(*this);
          return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,true,0,0,0,_width-1.0f,_height-1.0f,0.0f);
        } else {
          typename CImg<T>::_functor4d_streamline2d_directed func(*this);
          return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,false,0,0,0,_width-1.0f,_height-1.0f,0.0f);
        }
      }
      if (is_oriented_only) {
        typename CImg<T>::_functor4d_streamline3d_oriented func(*this);
        return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,true,0,0,0,_width-1.0f,_height-1.0f,_depth-1.0f);
      }
      typename CImg<T>::_functor4d_streamline3d_directed func(*this);
      return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,false,0,0,0,_width-1.0f,_height-1.0f,_depth-1.0f);
    }

    //! Return stream line of a 3d vector field.
    /**
       \param interpolation_type Type of interpolation (can be 0=nearest int, 1=linear, 2=2nd-order RK, 3=4th-order RK.

     **/
    template<typename tfunc>
    static CImg<floatT> streamline(const tfunc& func,
                                   const float x, const float y, const float z,
                                   const float L=256, const float dl=0.1f,
                                   const unsigned int interpolation_type=2, const bool is_backward_tracking=false,
                                   const bool is_oriented_only=false,
                                   const float x0=0, const float y0=0, const float z0=0,
                                   const float x1=0, const float y1=0, const float z1=0) {
      if (dl<=0)
        throw CImgArgumentException("CImg<%s>::streamline() : Invalid specified integration length %g "
                                    "(should be >0).",
                                    pixel_type(),
                                    dl);

      const bool is_bounded = (x0!=x1 || y0!=y1 || z0!=z1);
      if (L<=0 || (is_bounded && (x<x0 || x>x1 || y<y0 || y>y1 || z<z0 || z>z1))) return CImg<floatT>();
      const unsigned int size_L = (unsigned int)cimg::round(L/dl+1);
      CImg<floatT> coordinates(size_L,3);
      const float dl2 = dl/2;
      float
        *ptr_x = coordinates.data(0,0),
        *ptr_y = coordinates.data(0,1),
        *ptr_z = coordinates.data(0,2),
        pu = (float)(dl*func(x,y,z,0)),
        pv = (float)(dl*func(x,y,z,1)),
        pw = (float)(dl*func(x,y,z,2)),
        X = x, Y = y, Z = z;

      switch (interpolation_type) {
      case 0 : { // Nearest integer interpolation.
        cimg_forX(coordinates,l) {
          *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z;
          const int
            xi = (int)(X>0?X+0.5f:X-0.5f),
            yi = (int)(Y>0?Y+0.5f:Y-0.5f),
            zi = (int)(Z>0?Z+0.5f:Z-0.5f);
          float
            u = (float)(dl*func((float)xi,(float)yi,(float)zi,0)),
            v = (float)(dl*func((float)xi,(float)yi,(float)zi,1)),
            w = (float)(dl*func((float)xi,(float)yi,(float)zi,2));
          if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; }
          if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); }
          if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break;
        }
      } break;
      case 1 : { // First-order interpolation.
        cimg_forX(coordinates,l) {
          *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z;
          float
            u = (float)(dl*func(X,Y,Z,0)),
            v = (float)(dl*func(X,Y,Z,1)),
            w = (float)(dl*func(X,Y,Z,2));
          if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; }
          if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); }
          if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break;
        }
      } break;
      case 2 : { // Second order interpolation.
        cimg_forX(coordinates,l) {
          *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z;
          float
            u0 = (float)(dl2*func(X,Y,Z,0)),
            v0 = (float)(dl2*func(X,Y,Z,1)),
            w0 = (float)(dl2*func(X,Y,Z,2));
          if (is_oriented_only && u0*pu + v0*pv + w0*pw<0) { u0 = -u0; v0 = -v0; w0 = -w0; }
          float
            u = (float)(dl*func(X+u0,Y+v0,Z+w0,0)),
            v = (float)(dl*func(X+u0,Y+v0,Z+w0,1)),
            w = (float)(dl*func(X+u0,Y+v0,Z+w0,2));
          if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; }
          if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); }
          if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break;
        }
      } break;
      default : { // Fourth order interpolation.
        cimg_forX(coordinates,x) {
          *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z;
          float
            u0 = (float)(dl2*func(X,Y,Z,0)),
            v0 = (float)(dl2*func(X,Y,Z,1)),
            w0 = (float)(dl2*func(X,Y,Z,2));
          if (is_oriented_only && u0*pu + v0*pv + w0*pw<0) { u0 = -u0; v0 = -v0; w0 = -w0; }
          float
            u1 = (float)(dl2*func(X+u0,Y+v0,Z+w0,0)),
            v1 = (float)(dl2*func(X+u0,Y+v0,Z+w0,1)),
            w1 = (float)(dl2*func(X+u0,Y+v0,Z+w0,2));
          if (is_oriented_only && u1*pu + v1*pv + w1*pw<0) { u1 = -u1; v1 = -v1; w1 = -w1; }
          float
            u2 = (float)(dl2*func(X+u1,Y+v1,Z+w1,0)),
            v2 = (float)(dl2*func(X+u1,Y+v1,Z+w1,1)),
            w2 = (float)(dl2*func(X+u1,Y+v1,Z+w1,2));
          if (is_oriented_only && u2*pu + v2*pv + w2*pw<0) { u2 = -u2; v2 = -v2; w2 = -w2; }
          float
            u3 = (float)(dl2*func(X+u2,Y+v2,Z+w2,0)),
            v3 = (float)(dl2*func(X+u2,Y+v2,Z+w2,1)),
            w3 = (float)(dl2*func(X+u2,Y+v2,Z+w2,2));
          if (is_oriented_only && u2*pu + v2*pv + w2*pw<0) { u3 = -u3; v3 = -v3; w3 = -w3; }
          const float
            u = (u0 + u3)/3 + (u1 + u2)/1.5f,
            v = (v0 + v3)/3 + (v1 + v2)/1.5f,
            w = (w0 + w3)/3 + (w1 + w2)/1.5f;
          if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); }
          if (is_bounded && (X<x0 || X>x1 || Y<y0 || Y>y1 || Z<z0 || Z>z1)) break;
        }
      }
      }
      if (ptr_x!=coordinates.data(0,1)) coordinates.resize((int)(ptr_x-coordinates.data()),3,1,1,0);
      return coordinates;
    }

    //! Return stream line of a vector field.
    static CImg<floatT> streamline(const char *const expression,
                                   const float x, const float y, const float z,
                                   const float L=256, const float dl=0.1f,
                                   const unsigned int interpolation_type=2, const bool is_backward_tracking=true,
                                   const bool is_oriented_only=false,
                                   const float x0=0, const float y0=0, const float z0=0,
                                   const float x1=0, const float y1=0, const float z1=0) {
      _functor4d_streamline_expr func(expression);
      return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,is_oriented_only,x0,y0,z0,x1,y1,z1);
    }

    struct _functor4d_streamline2d_directed {
      const CImg<T>& ref;
      _functor4d_streamline2d_directed(const CImg<T>& pref):ref(pref) {}
      float operator()(const float x, const float y, const float z, const unsigned int c) const {
        return c<2?(float)ref._linear_atXY(x,y,(int)z,c):0;
      }
    };

    struct _functor4d_streamline3d_directed {
      const CImg<T>& ref;
      _functor4d_streamline3d_directed(const CImg<T>& pref):ref(pref) {}
      float operator()(const float x, const float y, const float z, const unsigned int c) const {
        return (float)ref._linear_atXYZ(x,y,z,c);
      }
    };

    struct _functor4d_streamline2d_oriented {
      const CImg<T>& ref;
      CImg<floatT> *pI;
      _functor4d_streamline2d_oriented(const CImg<T>& pref):ref(pref),pI(0) { pI = new CImg<floatT>(2,2,1,2); }
      ~_functor4d_streamline2d_oriented() { delete pI; }
      float operator()(const float x, const float y, const float z, const unsigned int c) const {
#define _cimg_vecalign2d(i,j) if (I(i,j,0)*I(0,0,0)+I(i,j,1)*I(0,0,1)<0) { I(i,j,0) = -I(i,j,0); I(i,j,1) = -I(i,j,1); }
        int
          xi = (int)x - (x>=0?0:1), nxi = xi + 1,
          yi = (int)y - (y>=0?0:1), nyi = yi + 1,
          zi = (int)z;
        const float
          dx = x - xi,
          dy = y - yi;
        if (c==0) {
          CImg<floatT>& I = *pI;
          if (xi<0) xi = 0; if (nxi<0) nxi = 0;
          if (xi>=ref.width()) xi = ref.width()-1; if (nxi>=ref.width()) nxi = ref.width()-1;
          if (yi<0) yi = 0; if (nyi<0) nyi = 0;
          if (yi>=ref.height()) yi = ref.height()-1; if (nyi>=ref.height()) nyi = ref.height()-1;
          I(0,0,0) = (float)ref(xi,yi,zi,0); I(0,0,1) = (float)ref(xi,yi,zi,1);
          I(1,0,0) = (float)ref(nxi,yi,zi,0); I(1,0,1) = (float)ref(nxi,yi,zi,1);
          I(1,1,0) = (float)ref(nxi,nyi,zi,0); I(1,1,1) = (float)ref(nxi,nyi,zi,1);
          I(0,1,0) = (float)ref(xi,nyi,zi,0); I(0,1,1) = (float)ref(xi,nyi,zi,1);
          _cimg_vecalign2d(1,0); _cimg_vecalign2d(1,1); _cimg_vecalign2d(0,1);
        }
        return c<2?(float)pI->_linear_atXY(dx,dy,0,c):0;
      }
    };

    struct _functor4d_streamline3d_oriented {
      const CImg<T>& ref;
      CImg<floatT> *pI;
      _functor4d_streamline3d_oriented(const CImg<T>& pref):ref(pref),pI(0) { pI = new CImg<floatT>(2,2,2,3); }
      ~_functor4d_streamline3d_oriented() { delete pI; }
      float operator()(const float x, const float y, const float z, const unsigned int c) const {
#define _cimg_vecalign3d(i,j,k) if (I(i,j,k,0)*I(0,0,0,0)+I(i,j,k,1)*I(0,0,0,1)+I(i,j,k,2)*I(0,0,0,2)<0) { \
  I(i,j,k,0) = -I(i,j,k,0); I(i,j,k,1) = -I(i,j,k,1); I(i,j,k,2) = -I(i,j,k,2); }
        int
          xi = (int)x - (x>=0?0:1), nxi = xi + 1,
          yi = (int)y - (y>=0?0:1), nyi = yi + 1,
          zi = (int)z - (z>=0?0:1), nzi = zi + 1;
        const float
          dx = x - xi,
          dy = y - yi,
          dz = z - zi;
        if (c==0) {
          CImg<floatT>& I = *pI;
          if (xi<0) xi = 0; if (nxi<0) nxi = 0;
          if (xi>=ref.width()) xi = ref.width()-1; if (nxi>=ref.width()) nxi = ref.width()-1;
          if (yi<0) yi = 0; if (nyi<0) nyi = 0;
          if (yi>=ref.height()) yi = ref.height()-1; if (nyi>=ref.height()) nyi = ref.height()-1;
          if (zi<0) zi = 0; if (nzi<0) nzi = 0;
          if (zi>=ref.depth()) zi = ref.depth()-1; if (nzi>=ref.depth()) nzi = ref.depth()-1;
          I(0,0,0,0) = (float)ref(xi,yi,zi,0); I(0,0,0,1) = (float)ref(xi,yi,zi,1); I(0,0,0,2) = (float)ref(xi,yi,zi,2);
          I(1,0,0,0) = (float)ref(nxi,yi,zi,0); I(1,0,0,1) = (float)ref(nxi,yi,zi,1); I(1,0,0,2) = (float)ref(nxi,yi,zi,2);
          I(1,1,0,0) = (float)ref(nxi,nyi,zi,0); I(1,1,0,1) = (float)ref(nxi,nyi,zi,1); I(1,1,0,2) = (float)ref(nxi,nyi,zi,2);
          I(0,1,0,0) = (float)ref(xi,nyi,zi,0); I(0,1,0,1) = (float)ref(xi,nyi,zi,1); I(0,1,0,2) = (float)ref(xi,yi,zi,2);
          I(0,0,0,1) = (float)ref(xi,yi,nzi,0); I(0,0,0,1) = (float)ref(xi,yi,nzi,1); I(0,0,0,2) = (float)ref(xi,yi,nzi,2);
          I(1,0,0,1) = (float)ref(nxi,yi,nzi,0); I(1,0,0,1) = (float)ref(nxi,yi,nzi,1); I(1,0,0,2) = (float)ref(nxi,yi,nzi,2);
          I(1,1,0,1) = (float)ref(nxi,nyi,nzi,0); I(1,1,0,1) = (float)ref(nxi,nyi,nzi,1); I(1,1,0,2) = (float)ref(nxi,nyi,nzi,2);
          I(0,1,0,1) = (float)ref(xi,nyi,nzi,0); I(0,1,0,1) = (float)ref(xi,nyi,nzi,1); I(0,1,0,2) = (float)ref(xi,yi,nzi,2);
          _cimg_vecalign3d(1,0,0); _cimg_vecalign3d(1,1,0); _cimg_vecalign3d(0,1,0);
          _cimg_vecalign3d(0,0,1); _cimg_vecalign3d(1,0,1); _cimg_vecalign3d(1,1,1); _cimg_vecalign3d(0,1,1);
        }
        return (float)pI->_linear_atXYZ(dx,dy,dz,c);
      }
    };

    struct _functor4d_streamline_expr {
      _cimg_math_parser *mp;
      ~_functor4d_streamline_expr() { delete mp; }
      _functor4d_streamline_expr(const char *const expr):mp(0) { mp = new _cimg_math_parser(CImg<T>::empty(),expr,"streamline"); }
      float operator()(const float x, const float y, const float z, const unsigned int c) const {
        return (float)mp->eval(x,y,z,c);
      }
    };

    //! Return an image containing the specified string.
    static CImg<T> string(const char *const str, const bool include_last_zero=true) {
      if (!str) return CImg<T>();
      return CImg<T>(str,std::strlen(str)+(include_last_zero?1:0));
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0) {
      _cimg_static CImg<T> r(1,1);
      r[0] = a0;
      return r;
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0, const T& a1) {
      _cimg_static CImg<T> r(1,2); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1;
      return r;
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2) {
      _cimg_static CImg<T> r(1,3); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
      return r;
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3) {
      _cimg_static CImg<T> r(1,4); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      return r;
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
      _cimg_static CImg<T> r(1,5); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
      return r;
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) {
      _cimg_static CImg<T> r(1,6); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
      return r;
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
                          const T& a4, const T& a5, const T& a6) {
      _cimg_static CImg<T> r(1,7); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6;
      return r;
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
                          const T& a4, const T& a5, const T& a6, const T& a7) {
      _cimg_static CImg<T> r(1,8); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
      return r;
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
                          const T& a4, const T& a5, const T& a6, const T& a7,
                          const T& a8) {
      _cimg_static CImg<T> r(1,9); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
      *(ptr++) = a8;
      return r;
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
                          const T& a4, const T& a5, const T& a6, const T& a7,
                          const T& a8, const T& a9) {
      _cimg_static CImg<T> r(1,10); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
      *(ptr++) = a8; *(ptr++) = a9;
      return r;
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
                          const T& a4, const T& a5, const T& a6, const T& a7,
                          const T& a8, const T& a9, const T& a10) {
      _cimg_static CImg<T> r(1,11); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10;
      return r;
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
                          const T& a4, const T& a5, const T& a6, const T& a7,
                          const T& a8, const T& a9, const T& a10, const T& a11) {
      _cimg_static CImg<T> r(1,12); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
      return r;
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
                          const T& a4, const T& a5, const T& a6, const T& a7,
                          const T& a8, const T& a9, const T& a10, const T& a11,
                          const T& a12) {
      _cimg_static CImg<T> r(1,13); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
      *(ptr++) = a12;
      return r;
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
                          const T& a4, const T& a5, const T& a6, const T& a7,
                          const T& a8, const T& a9, const T& a10, const T& a11,
                          const T& a12, const T& a13) {
      _cimg_static CImg<T> r(1,14); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
      *(ptr++) = a12; *(ptr++) = a13;
      return r;
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
                          const T& a4, const T& a5, const T& a6, const T& a7,
                          const T& a8, const T& a9, const T& a10, const T& a11,
                          const T& a12, const T& a13, const T& a14) {
      _cimg_static CImg<T> r(1,15); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
      *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
      return r;
    }

    //! Return a vector with specified coefficients.
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
                          const T& a4, const T& a5, const T& a6, const T& a7,
                          const T& a8, const T& a9, const T& a10, const T& a11,
                          const T& a12, const T& a13, const T& a14, const T& a15) {
      _cimg_static CImg<T> r(1,16); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
      *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
      return r;
    }

    //! Return a 1x1 square matrix with specified coefficients.
    static CImg<T> matrix(const T& a0) {
      return vector(a0);
    }

    //! Return a 2x2 square matrix with specified coefficients.
    static CImg<T> matrix(const T& a0, const T& a1,
                          const T& a2, const T& a3) {
      _cimg_static CImg<T> r(2,2); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1;
      *(ptr++) = a2; *(ptr++) = a3;
      return r;
    }

    //! Return a 3x3 square matrix with specified coefficients.
    static CImg<T> matrix(const T& a0, const T& a1, const T& a2,
                          const T& a3, const T& a4, const T& a5,
                          const T& a6, const T& a7, const T& a8) {
      _cimg_static CImg<T> r(3,3); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
      *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
      *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8;
      return r;
    }

    //! Return a 4x4 square matrix with specified coefficients.
    static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3,
                          const T& a4, const T& a5, const T& a6, const T& a7,
                          const T& a8, const T& a9, const T& a10, const T& a11,
                          const T& a12, const T& a13, const T& a14, const T& a15) {
      _cimg_static CImg<T> r(4,4); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
      *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
      return r;
    }

    //! Return a 5x5 square matrix with specified coefficients.
    static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4,
                          const T& a5, const T& a6, const T& a7, const T& a8, const T& a9,
                          const T& a10, const T& a11, const T& a12, const T& a13, const T& a14,
                          const T& a15, const T& a16, const T& a17, const T& a18, const T& a19,
                          const T& a20, const T& a21, const T& a22, const T& a23, const T& a24) {
      _cimg_static CImg<T> r(5,5); T *ptr = r._data;
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
      *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9;
      *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
      *(ptr++) = a15; *(ptr++) = a16; *(ptr++) = a17; *(ptr++) = a18; *(ptr++) = a19;
      *(ptr++) = a20; *(ptr++) = a21; *(ptr++) = a22; *(ptr++) = a23; *(ptr++) = a24;
      return r;
    }

    //! Return a 1x1 symmetric matrix with specified coefficients.
    static CImg<T> tensor(const T& a1) {
      return matrix(a1);
    }

    //! Return a 2x2 symmetric matrix tensor with specified coefficients.
    static CImg<T> tensor(const T& a1, const T& a2, const T& a3) {
      return matrix(a1,a2,a2,a3);
    }

    //! Return a 3x3 symmetric matrix with specified coefficients.
    static CImg<T> tensor(const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6) {
      return matrix(a1,a2,a3,a2,a4,a5,a3,a5,a6);
    }

    //! Return a 1x1 diagonal matrix with specified coefficients.
    static CImg<T> diagonal(const T& a0) {
      return matrix(a0);
    }

    //! Return a 2x2 diagonal matrix with specified coefficients.
    static CImg<T> diagonal(const T& a0, const T& a1) {
      return matrix(a0,0,0,a1);
    }

    //! Return a 3x3 diagonal matrix with specified coefficients.
    static CImg<T> diagonal(const T& a0, const T& a1, const T& a2) {
      return matrix(a0,0,0,0,a1,0,0,0,a2);
    }

    //! Return a 4x4 diagonal matrix with specified coefficients.
    static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3) {
      return matrix(a0,0,0,0,0,a1,0,0,0,0,a2,0,0,0,0,a3);
    }

    //! Return a 5x5 diagonal matrix with specified coefficients.
    static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
      return matrix(a0,0,0,0,0,0,a1,0,0,0,0,0,a2,0,0,0,0,0,a3,0,0,0,0,0,a4);
    }

    //! Return a NxN identity matrix.
    static CImg<T> identity_matrix(const unsigned int N) {
      CImg<T> res(N,N,1,1,0);
      cimg_forX(res,x) res(x,x) = 1;
      return res;
    }

    //! Return a N-numbered sequence vector from \p a0 to \p a1.
    static CImg<T> sequence(const unsigned int N, const T a0, const T a1) {
      if (N) return CImg<T>(1,N).sequence(a0,a1);
      return CImg<T>();
    }

    //! Return a 3x3 rotation matrix along the (x,y,z)-axis with an angle w.
    static CImg<T> rotation_matrix(const float x, const float y, const float z, const float w, const bool quaternion_data=false) {
      float X,Y,Z,W;
      if (!quaternion_data) {
        const float norm = (float)std::sqrt(x*x + y*y + z*z),
          nx = norm>0?x/norm:0,
          ny = norm>0?y/norm:0,
          nz = norm>0?z/norm:1,
          nw = norm>0?w:0,
          sina = (float)std::sin(nw/2),
          cosa = (float)std::cos(nw/2);
        X = nx*sina;
        Y = ny*sina;
        Z = nz*sina;
        W = cosa;
      } else {
        const float norm = (float)std::sqrt(x*x + y*y + z*z + w*w);
        if (norm>0) { X = x/norm; Y = y/norm; Z = z/norm; W = w/norm; }
        else { X = Y = Z = 0; W = 1; }
      }
      const float xx = X*X, xy = X*Y, xz = X*Z, xw = X*W, yy = Y*Y, yz = Y*Z, yw = Y*W, zz = Z*Z, zw = Z*W;
      return CImg<T>::matrix((T)(1-2*(yy+zz)), (T)(2*(xy+zw)),   (T)(2*(xz-yw)),
                             (T)(2*(xy-zw)),   (T)(1-2*(xx+zz)), (T)(2*(yz+xw)),
                             (T)(2*(xz+yw)),   (T)(2*(yz-xw)),   (T)(1-2*(xx+yy)));
    }

    //@}
    //-----------------------------------
    //
    //! \name Value Manipulation
    //@{
    //-----------------------------------

    //! Fill an image by a value \p val.
    /**
       \param val = fill value
       \note All pixel values of the image instance will be initialized by \p val.
    **/
    CImg<T>& fill(const T val) {
      if (is_empty()) return *this;
      if (val && sizeof(T)!=1) cimg_for(*this,ptrd,T) *ptrd = val;
      else std::memset(_data,(int)val,size()*sizeof(T));
      return *this;
    }

    CImg<T> get_fill(const T val) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val);
    }

    //! Fill sequentially all pixel values with values \a val0 and \a val1 respectively.
    CImg<T>& fill(const T val0, const T val1) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end()-1;
      for (ptrd = _data; ptrd<ptre; ) { *(ptrd++) = val0; *(ptrd++) = val1; }
      if (ptrd!=ptre+1) *(ptrd++) = val0;
      return *this;
    }

    CImg<T> get_fill(const T val0, const T val1) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1);
    }

    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2.
    CImg<T>& fill(const T val0, const T val1, const T val2) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end()-2;
      for (ptrd = _data; ptrd<ptre; ) { *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; }
      ptre+=2;
      switch (ptre - ptrd) {
      case 2 : *(--ptre) = val1;
      case 1 : *(--ptre) = val0;
      }
      return *this;
    }

    CImg<T> get_fill(const T val0, const T val1, const T val2) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2);
    }

    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3.
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end()-3;
      for (ptrd = _data; ptrd<ptre; ) { *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; }
      ptre+=3;
      switch (ptre - ptrd) {
      case 3 : *(--ptre) = val2;
      case 2 : *(--ptre) = val1;
      case 1 : *(--ptre) = val0;
      }
      return *this;
    }

    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3);
    }

    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4.
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end()-4;
      for (ptrd = _data; ptrd<ptre; ) { *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; }
      ptre+=4;
      switch (ptre - ptrd) {
      case 4 : *(--ptre) = val3;
      case 3 : *(--ptre) = val2;
      case 2 : *(--ptre) = val1;
      case 1 : *(--ptre) = val0;
      }
      return *this;
    }

    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4);
    }

    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4 and \a val5.
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end()-5;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;
      }
      ptre+=5;
      switch (ptre - ptrd) {
      case 5 : *(--ptre) = val4;
      case 4 : *(--ptre) = val3;
      case 3 : *(--ptre) = val2;
      case 2 : *(--ptre) = val1;
      case 1 : *(--ptre) = val0;
      }
      return *this;
    }

    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5);
    }

    //! Fill sequentially pixel values.
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end()-6;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5; *(ptrd++) = val6;
      }
      ptre+=6;
      switch (ptre - ptrd) {
      case 6 : *(--ptre) = val5;
      case 5 : *(--ptre) = val4;
      case 4 : *(--ptre) = val3;
      case 3 : *(--ptre) = val2;
      case 2 : *(--ptre) = val1;
      case 1 : *(--ptre) = val0;
      }
      return *this;
    }

    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6);
    }

    //! Fill sequentially pixel values.
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                  const T val7) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end()-7;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3;
        *(ptrd++) = val4; *(ptrd++) = val5; *(ptrd++) = val6; *(ptrd++) = val7;
      }
      ptre+=7;
      switch (ptre - ptrd) {
      case 7 : *(--ptre) = val6;
      case 6 : *(--ptre) = val5;
      case 5 : *(--ptre) = val4;
      case 4 : *(--ptre) = val3;
      case 3 : *(--ptre) = val2;
      case 2 : *(--ptre) = val1;
      case 1 : *(--ptre) = val0;
      }
      return *this;
    }

    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                     const T val7) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7);
    }

    //! Fill sequentially pixel values.
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                  const T val7, const T val8) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end()-8;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2;
        *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;
        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8;
      }
      ptre+=8;
      switch (ptre - ptrd) {
      case 8 : *(--ptre) = val7;
      case 7 : *(--ptre) = val6;
      case 6 : *(--ptre) = val5;
      case 5 : *(--ptre) = val4;
      case 4 : *(--ptre) = val3;
      case 3 : *(--ptre) = val2;
      case 2 : *(--ptre) = val1;
      case 1 : *(--ptre) = val0;
      }
      return *this;
    }

    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                     const T val7, const T val8) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8);
    }

    //! Fill sequentially pixel values.
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                  const T val7, const T val8, const T val9) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end()-9;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4;
        *(ptrd++) = val5; *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9;
      }
      ptre+=9;
      switch (ptre - ptrd) {
      case 9 : *(--ptre) = val8;
      case 8 : *(--ptre) = val7;
      case 7 : *(--ptre) = val6;
      case 6 : *(--ptre) = val5;
      case 5 : *(--ptre) = val4;
      case 4 : *(--ptre) = val3;
      case 3 : *(--ptre) = val2;
      case 2 : *(--ptre) = val1;
      case 1 : *(--ptre) = val0;
      }
      return *this;
    }

    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                     const T val7, const T val8, const T val9) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9);
    }

    //! Fill sequentially pixel values.
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                  const T val7, const T val8, const T val9, const T val10) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end()-10;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4;
        *(ptrd++) = val5; *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9;
        *(ptrd++) = val10;
      }
      ptre+=10;
      switch (ptre - ptrd) {
      case 10 : *(--ptre) = val9;
      case 9 : *(--ptre) = val8;
      case 8 : *(--ptre) = val7;
      case 7 : *(--ptre) = val6;
      case 6 : *(--ptre) = val5;
      case 5 : *(--ptre) = val4;
      case 4 : *(--ptre) = val3;
      case 3 : *(--ptre) = val2;
      case 2 : *(--ptre) = val1;
      case 1 : *(--ptre) = val0;
      }
      return *this;
    }

    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                     const T val7, const T val8, const T val9, const T val10) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10);
    }

    //! Fill sequentially pixel values.
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                  const T val7, const T val8, const T val9, const T val10, const T val11) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end()-11;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;
        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11;
      }
      ptre+=11;
      switch (ptre - ptrd) {
      case 11 : *(--ptre) = val10;
      case 10 : *(--ptre) = val9;
      case 9 : *(--ptre) = val8;
      case 8 : *(--ptre) = val7;
      case 7 : *(--ptre) = val6;
      case 6 : *(--ptre) = val5;
      case 5 : *(--ptre) = val4;
      case 4 : *(--ptre) = val3;
      case 3 : *(--ptre) = val2;
      case 2 : *(--ptre) = val1;
      case 1 : *(--ptre) = val0;
      }
      return *this;
    }

    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                     const T val7, const T val8, const T val9, const T val10, const T val11) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11);
    }

    //! Fill sequentially pixel values.
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end()-12;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;
        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11;
        *(ptrd++) = val12;
      }
      ptre+=12;
      switch (ptre - ptrd) {
      case 12 : *(--ptre) = val11;
      case 11 : *(--ptre) = val10;
      case 10 : *(--ptre) = val9;
      case 9 : *(--ptre) = val8;
      case 8 : *(--ptre) = val7;
      case 7 : *(--ptre) = val6;
      case 6 : *(--ptre) = val5;
      case 5 : *(--ptre) = val4;
      case 4 : *(--ptre) = val3;
      case 3 : *(--ptre) = val2;
      case 2 : *(--ptre) = val1;
      case 1 : *(--ptre) = val0;
      }
      return *this;
    }

    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                     const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12);
    }

    //! Fill sequentially pixel values.
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
                  const T val13) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end()-13;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;
        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11;
        *(ptrd++) = val12; *(ptrd++) = val13;
      }
      ptre+=13;
      switch (ptre - ptrd) {
      case 13 : *(--ptre) = val12;
      case 12 : *(--ptre) = val11;
      case 11 : *(--ptre) = val10;
      case 10 : *(--ptre) = val9;
      case 9 : *(--ptre) = val8;
      case 8 : *(--ptre) = val7;
      case 7 : *(--ptre) = val6;
      case 6 : *(--ptre) = val5;
      case 5 : *(--ptre) = val4;
      case 4 : *(--ptre) = val3;
      case 3 : *(--ptre) = val2;
      case 2 : *(--ptre) = val1;
      case 1 : *(--ptre) = val0;
      }
      return *this;
    }

    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                     const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
                     const T val13) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
                                                  val13);
    }

    //! Fill sequentially pixel values.
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
                  const T val13, const T val14) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end()-14;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;
        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11;
        *(ptrd++) = val12; *(ptrd++) = val13; *(ptrd++) = val14;
      }
      ptre+=14;
      switch (ptre - ptrd) {
      case 14 : *(--ptre) = val13;
      case 13 : *(--ptre) = val12;
      case 12 : *(--ptre) = val11;
      case 11 : *(--ptre) = val10;
      case 10 : *(--ptre) = val9;
      case 9 : *(--ptre) = val8;
      case 8 : *(--ptre) = val7;
      case 7 : *(--ptre) = val6;
      case 6 : *(--ptre) = val5;
      case 5 : *(--ptre) = val4;
      case 4 : *(--ptre) = val3;
      case 3 : *(--ptre) = val2;
      case 2 : *(--ptre) = val1;
      case 1 : *(--ptre) = val0;
      }
      return *this;
    }

    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                     const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
                     const T val13, const T val14) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
                                                  val13,val14);
    }

    //! Fill sequentially pixel values.
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
                  const T val13, const T val14, const T val15) {
      if (is_empty()) return *this;
      T *ptrd, *ptre = end()-15;
      for (ptrd = _data; ptrd<ptre; ) {
        *(ptrd++) = val0; *(ptrd++) = val1; *(ptrd++) = val2; *(ptrd++) = val3; *(ptrd++) = val4; *(ptrd++) = val5;
        *(ptrd++) = val6; *(ptrd++) = val7; *(ptrd++) = val8; *(ptrd++) = val9; *(ptrd++) = val10; *(ptrd++) = val11;
        *(ptrd++) = val12; *(ptrd++) = val13; *(ptrd++) = val14; *(ptrd++) = val15;
      }
      ptre+=15;
      switch (ptre - ptrd) {
      case 15 : *(--ptre) = val14;
      case 14 : *(--ptre) = val13;
      case 13 : *(--ptre) = val12;
      case 12 : *(--ptre) = val11;
      case 11 : *(--ptre) = val10;
      case 10 : *(--ptre) = val9;
      case 9 : *(--ptre) = val8;
      case 8 : *(--ptre) = val7;
      case 7 : *(--ptre) = val6;
      case 6 : *(--ptre) = val5;
      case 5 : *(--ptre) = val4;
      case 4 : *(--ptre) = val3;
      case 3 : *(--ptre) = val2;
      case 2 : *(--ptre) = val1;
      case 1 : *(--ptre) = val0;
      }
      return *this;
    }

    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
                     const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
                     const T val13, const T val14, const T val15) const {
      return CImg<T>(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
                                                  val13,val14,val15);
    }

    //! Fill image values according to the given expression, which can be a formula or a list of values.
    CImg<T>& fill(const char *const expression, const bool repeat_flag) {
      if (is_empty() || !expression || !*expression) return *this;
      const unsigned int omode = cimg::exception_mode();
      cimg::exception_mode() = 0;
      try { // Try to fill values according to a formula.
        const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
        _cimg_math_parser mp(base,expression,"fill");
        T *ptrd = _data;
        cimg_forXYZC(*this,x,y,z,c) *(ptrd++) = (T)mp.eval((double)x,(double)y,(double)z,(double)c);
      } catch (CImgException& e) { // If failed, try to recognize a list of values.
        char item[16384] = { 0 }, sep = 0;
        const char *nexpression = expression;
        unsigned int nb = 0; const unsigned int siz = size();
        T *ptrd = _data;
        for (double val = 0; *nexpression && nb<siz; ++nb) {
          sep = 0;
          const int err = std::sscanf(nexpression,"%4095[ \n\t0-9.e+-]%c",item,&sep);
          if (err>0 && std::sscanf(item,"%lf",&val)==1) {
            nexpression+=std::strlen(item) + (err>1?1:0);
            *(ptrd++) = (T)val;
          } else break;
        }
        cimg::exception_mode() = omode;
        if (nb<siz && (sep || *nexpression))
          throw CImgArgumentException(e.what(),pixel_type(),expression);
        if (repeat_flag && nb && nb<siz) for (T *ptrs = _data, *const ptre = _data + siz; ptrd<ptre; ++ptrs) *(ptrd++) = *ptrs;
      }
      cimg::exception_mode() = omode;
      return *this;
    }

    CImg<T> get_fill(const char *const values, const bool repeat_values) const {
      return (+*this).fill(values,repeat_values);
    }

    //! Fill image values according to the values found in the specified image.
    template<typename t>
    CImg<T>& fill(const CImg<t>& values, const bool repeat_values=true) {
      if (is_empty() || !values) return *this;
      T *ptrd = _data, *ptre = ptrd + size();
      for (t *ptrs = values._data, *ptrs_end = ptrs + values.size(); ptrs<ptrs_end && ptrd<ptre; ++ptrs) *(ptrd++) = (T)*ptrs;
      if (repeat_values && ptrd<ptre) for (T *ptrs = _data; ptrd<ptre; ++ptrs) *(ptrd++) = *ptrs;
      return *this;
    }

    template<typename t>
    CImg<T> get_fill(const CImg<t>& values, const bool repeat_values=true) const {
      return repeat_values?CImg<T>(_width,_height,_depth,_spectrum).fill(values,repeat_values):(+*this).fill(values,repeat_values);
    }

    //! Fill image values along the X-axis at the specified pixel position (y,z,c).
    CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int c, const int a0, ...) {
#define _cimg_fill1(x,y,z,c,off,siz,t) { \
    va_list ap; va_start(ap,a0); T *ptrd = data(x,y,z,c); *ptrd = (T)a0; \
    for (unsigned int k = 1; k<siz; ++k) { ptrd+=off; *ptrd = (T)va_arg(ap,t); } \
    va_end(ap); }
      if (y<_height && z<_depth && c<_spectrum) _cimg_fill1(0,y,z,c,1,_width,int);
      return *this;
    }

    CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int c, const double a0, ...) {
      if (y<_height && z<_depth && c<_spectrum) _cimg_fill1(0,y,z,c,1,_width,double);
      return *this;
    }

    //! Fill image values along the Y-axis at the specified pixel position (x,z,c).
    CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int c, const int a0, ...) {
      if (x<_width && z<_depth && c<_spectrum) _cimg_fill1(x,0,z,c,_width,_height,int);
      return *this;
    }

    CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int c, const double a0, ...) {
      if (x<_width && z<_depth && c<_spectrum) _cimg_fill1(x,0,z,c,_width,_height,double);
      return *this;
    }

    //! Fill image values along the Z-axis at the specified pixel position (x,y,c).
    CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int c, const int a0, ...) {
      const unsigned int wh = _width*_height;
      if (x<_width && y<_height && c<_spectrum) _cimg_fill1(x,y,0,c,wh,_depth,int);
      return *this;
    }

    CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int c, const double a0, ...) {
      const unsigned int wh = _width*_height;
      if (x<_width && y<_height && c<_spectrum) _cimg_fill1(x,y,0,c,wh,_depth,double);
      return *this;
    }

    //! Fill image values along the C-axis at the specified pixel position (x,y,z).
    CImg<T>& fillC(const unsigned int x, const unsigned int y, const unsigned int z, const int a0, ...) {
      const unsigned int whd = _width*_height*_depth;
      if (x<_width && y<_height && z<_depth) _cimg_fill1(x,y,z,0,whd,_spectrum,int);
      return *this;
    }

    CImg<T>& fillC(const unsigned int x, const unsigned int y, const unsigned int z, const double a0, ...) {
      const unsigned int whd = _width*_height*_depth;
      if (x<_width && y<_height && z<_depth) _cimg_fill1(x,y,z,0,whd,_spectrum,double);
      return *this;
    }

    //! Remove specified value from the image buffer, and return resulting buffer as a one-column vector.
    CImg<T>& discard(const T value) {
      return get_discard(value).move_to(*this);
    }

    CImg<T> get_discard(const T value) const {
      CImg<T> res(1,size());
      T *pd = res._data;
      for (const T *ps = _data, *const pse = end(); ps<pse; ++ps)
        if (*ps!=value) *(pd++) = *ps;
      if (pd==res._data) return CImg<T>();
      return res.resize(1,pd-res._data,1,1,-1);
    }

    //! Remove specified values sequence from the image buffer, and return resulting buffer as a one-column vector.
    template<typename t>
    CImg<T>& discard(const CImg<t>& values) {
      return get_discard(values).move_to(*this);
    }

    template<typename t>
    CImg<T> get_discard(const CImg<t>& values) const {
      if (!values) return *this;
      if (values.size()==1) return get_discard(*values);
      CImg<T> res(1,size());
      T *pd = res._data;
      const t *const pve = values.end();
      for (const T *ps = _data, *const pse = end(); ps<pse; ) {
        const T *_ps = ps;
        const t *pv = values._data;
        while (_ps<pse && pv<pve) { if (*(_ps++)!=(T)*pv) break; ++pv; }
        if (pv!=pve) {
          const unsigned int l = _ps - ps;
          if (l==1) *(pd++) = *ps; else { std::memcpy(pd,ps,sizeof(T)*l); pd+=l; }
        }
        ps = _ps;
      }
      if (pd==res._data) return CImg<T>();
      return res.resize(1,pd-res._data,1,1,-1);
    }

    //! Invert endianness of the image buffer.
    CImg<T>& invert_endianness() {
      cimg::invert_endianness(_data,size());
      return *this;
    }

    CImg<T> get_invert_endianness() const {
      return (+*this).invert_endianness();
    }

    //! Fill the image instance with random values between specified range.
    CImg<T>& rand(const T val_min, const T val_max) {
      const float delta = (float)val_max - (float)val_min;
      cimg_for(*this,ptrd,T) *ptrd = (T)(val_min + cimg::rand()*delta);
      return *this;
    }

    CImg<T> get_rand(const T val_min, const T val_max) const {
      return (+*this).rand(val_min,val_max);
    }

    //! Compute image with rounded pixel values.
    /**
       \param y Rounding precision.
       \param rounding_type Roundin type, can be 0 (nearest), 1 (forward), -1(backward).
    **/
    CImg<T>& round(const double y=1, const int rounding_type=0) {
      if (y>0) cimg_for(*this,ptrd,T) *ptrd = cimg::round(*ptrd,y,rounding_type);
      return *this;
    }

    CImg<T> get_round(const double y=1, const unsigned int rounding_type=0) const {
      return (+*this).round(y,rounding_type);
    }

    //! Add random noise to the values of the image instance.
    /**
       \param sigma Amplitude of the random additive noise. If \p sigma<0, it stands for a percentage of the global value range.
       \param noise_type Type of additive noise (can be \p 0=gaussian, \p 1=uniform, \p 2=Salt and Pepper, \p 3=Poisson or \p 4=Rician).
       \return A reference to the modified image instance.
       \note
       - For Poisson noise (\p noise_type=3), parameter \p sigma is ignored, as Poisson noise only depends on the image value itself.
       - Function \p CImg<T>::get_noise() is also defined. It returns a non-shared modified copy of the image instance.
       \par Sample code :
       \code
       const CImg<float> img("reference.jpg"), res = img.get_noise(40);
       (img,res.normalize(0,255)).display();
       \endcode
       \image html ref_noise.jpg
    **/
    CImg<T>& noise(const double sigma, const unsigned int noise_type=0) {
      if (!is_empty()) {
        const Tfloat vmin = (Tfloat)cimg::type<T>::min(), vmax = (Tfloat)cimg::type<T>::max();
        Tfloat nsigma = (Tfloat)sigma, m = 0, M = 0;
        if (nsigma==0 && noise_type!=3) return *this;
        if (nsigma<0 || noise_type==2) m = (Tfloat)min_max(M);
        if (nsigma<0) nsigma = (Tfloat)(-nsigma*(M-m)/100.0);
        switch (noise_type) {
        case 0 : { // Gaussian noise
          cimg_for(*this,ptrd,T) {
            Tfloat val = (Tfloat)(*ptrd + nsigma*cimg::grand());
            if (val>vmax) val = vmax;
            if (val<vmin) val = vmin;
            *ptrd = (T)val;
          }
        } break;
        case 1 : { // Uniform noise
          cimg_for(*this,ptrd,T) {
            Tfloat val = (Tfloat)(*ptrd + nsigma*cimg::crand());
            if (val>vmax) val = vmax;
            if (val<vmin) val = vmin;
            *ptrd = (T)val;
          }
        } break;
        case 2 : { // Salt & Pepper noise
          if (nsigma<0) nsigma = -nsigma;
          if (M==m) { m = 0; M = (Tfloat)(cimg::type<T>::is_float()?1:cimg::type<T>::max()); }
          cimg_for(*this,ptrd,T) if (cimg::rand()*100<nsigma) *ptrd = (T)(cimg::rand()<0.5?M:m);
        } break;

        case 3 : { // Poisson Noise
          cimg_for(*this,ptrd,T) *ptrd = (T)cimg::prand(*ptrd);
        } break;

        case 4 : { // Rice noise
          const Tfloat sqrt2 = (Tfloat)std::sqrt(2.0);
          cimg_for(*this,ptrd,T) {
            const Tfloat
              val0 = (Tfloat)*ptrd/sqrt2,
              re = (Tfloat)(val0 + nsigma*cimg::grand()),
              im = (Tfloat)(val0 + nsigma*cimg::grand());
            Tfloat val = (Tfloat)std::sqrt(re*re + im*im);
            if (val>vmax) val = vmax;
            if (val<vmin) val = vmin;
            *ptrd = (T)val;
          }
        } break;
        default :
          throw CImgArgumentException(_cimg_instance
                                      "noise() : Invalid specified noise type %d "
                                      "(should be { 0=gaussian | 1=uniform | 2=salt&Pepper | 3=poisson }).",
                                      cimg_instance,
                                      noise_type);
        }
      }
      return *this;
    }

    CImg<T> get_noise(const double sigma, const unsigned int noise_type=0) const {
      return (+*this).noise(sigma,noise_type);
    }

    //! Linearly normalize values of the image instance between \p value_min and \p value_max.
    /**
       \param value_min Minimum desired value of the resulting image.
       \param value_max Maximum desired value of the resulting image.
       \return A reference to the modified image instance.
       \note
       - Function \p CImg<T>::get_normalize() is also defined. It returns a non-shared modified copy of the image instance.
       \par Sample code :
       \code
       const CImg<float> img("reference.jpg"), res = img.get_normalize(160,220);
       (img,res).display();
       \endcode
       \image html ref_normalize2.jpg
    **/
    CImg<T>& normalize(const T value_min, const T value_max) {
      if (is_empty()) return *this;
      const T a = value_min<value_max?value_min:value_max, b = value_min<value_max?value_max:value_min;
      T m, M = max_min(m);
      const Tfloat fm = (Tfloat)m, fM = (Tfloat)M;
      if (m==M) return fill(value_min);
      if (m!=a || M!=b) cimg_for(*this,ptrd,T) *ptrd = (T)((*ptrd-fm)/(fM-fm)*(b-a)+a);
      return *this;
    }

    CImg<Tfloat> get_normalize(const T value_min, const T value_max) const {
      return CImg<Tfloat>(*this,false).normalize((Tfloat)value_min,(Tfloat)value_max);
    }

    //! Normalize multi-valued pixels of the image instance, with respect to their L2-norm.
    /**
       \return A reference to the modified image instance.
       \note
       - Function \p CImg<T>::get_normalize() is also defined. It returns a non-shared modified copy of the image instance.
       \par Sample code :
       \code
       const CImg<float> img("reference.jpg"), res = img.get_normalize();
       (img,res.normalize(0,255)).display();
       \endcode
       \image html ref_normalize.jpg
    **/
    CImg<T>& normalize() {
      T *ptrd = _data;
      const unsigned int whd = _width